From 5b8b15db73df337c4e3772c04c5676635da8bcdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?= Date: Wed, 26 Jul 2023 20:30:00 -0500 Subject: [PATCH] feat: support initializer --- .gdb_history | 55 ------- .gitignore | 1 + .vscode/settings.json | 7 +- ccc.h | 22 ++- codegen.c | 18 ++- parse.c | 354 ++++++++++++++++++++++++++++++++++++++---- tests | 138 +++++++++++++++- tokenize.c | 18 ++- 8 files changed, 515 insertions(+), 98 deletions(-) delete mode 100644 .gdb_history diff --git a/.gdb_history b/.gdb_history deleted file mode 100644 index 3458a3a..0000000 --- a/.gdb_history +++ /dev/null @@ -1,55 +0,0 @@ -run test -b main -run test -n -b gen -run test -c -n -s -q -r test -b main -r test -n -n -r -n -r -m -n -s -n -b function -r -c -n -s -n -b stmt -c -r -c -c -r -c -n -i -s -n -b stmt -r test -n -s cur -p cur -p sc -p *cur -n -p parse.c::cur -p 'parse.c'::cur -n -r -n -c -n -n diff --git a/.gitignore b/.gitignore index adc6fd1..4f2d58e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ tmp* # for debug test +.gdb_history diff --git a/.vscode/settings.json b/.vscode/settings.json index ed8cb28..b07e718 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,13 @@ { "files.associations": { "*.v": "coq", + "*.asm": "gas", + "*.ts": "typescript", + "*.pl": "prolog", + "*.plt": "prolog", "stdbool.h": "c", - "tests": "cpp" + "tests": "cpp", + "initializer_list": "c" }, "C_Cpp.default.configurationProvider": "ms-vscode.makefile-tools" } \ No newline at end of file diff --git a/ccc.h b/ccc.h index 3bb3df9..5facb8b 100644 --- a/ccc.h +++ b/ccc.h @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,6 +9,7 @@ #include typedef struct Type Type; typedef struct Member Member; +typedef struct Initializer Initializer; // // tokenize.c // @@ -33,6 +35,7 @@ struct Token { void error(char *fmt, ...); void error_at(char *loc, char *fmt, ...); void error_tok(Token *tok, char *fmt, ...); +void warn_tok(Token *tok, char *fmt, ...); Token *peek(char *s); Token *consume(char *op); char *strndup(char *p, int len); @@ -59,8 +62,7 @@ struct Var { // local variable int offset; // Offset from RBP // global variable - char *contents; - int cont_len; + Initializer *initializer; }; typedef struct VarList VarList; struct VarList { @@ -158,11 +160,27 @@ struct Node { Member *member; }; +// global variable initializer +// global variable 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; + long addend; +}; + typedef struct Function Function; struct Function { Function *next; char *name; VarList *params; + bool is_static; Node *node; VarList *locals; int stack_size; diff --git a/codegen.c b/codegen.c index 7c53aac..ca2c39a 100644 --- a/codegen.c +++ b/codegen.c @@ -554,12 +554,20 @@ void emit_data(Program *prog) { for (VarList *vl = prog->globals; vl; vl = vl->next) { Var *var = vl->var; printf("%s:\n", var->name); - if (!var->contents) { + if (!var->initializer) { printf(" .zero %d\n", size_of(var->ty, var->tok)); 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%+ld\n", init->label, init->addend); + continue; + } + if (init->sz == 1) { + printf(" .byte %ld\n", init->val); + } else { + printf(" .%dbyte %ld\n", init->sz, init->val); + } } } } @@ -567,7 +575,9 @@ void emit_data(Program *prog) { void emit_text(Program *prog) { printf(".text\n"); for (Function *fn = prog->fns; fn; fn = fn->next) { - printf(".global %s\n", fn->name); + if (!fn->is_static) { + printf(".global %s\n", fn->name); + } printf("%s:\n", fn->name); funcname = fn->name; diff --git a/parse.c b/parse.c index 5c6e04d..ccf8b74 100644 --- a/parse.c +++ b/parse.c @@ -160,6 +160,8 @@ Node *declaration(); bool is_typename(); Node *stmt(); Node *expr(); +long eval(Node *node); +long eval2(Node *node, Var **var); long const_expr(); Node *assign(); Node *conditional(); @@ -190,7 +192,7 @@ bool is_function() { return isfunc; } -// program = (global_var | function)* +// program = (global-var | function)* Program *program() { Function head; head.next = NULL; @@ -550,6 +552,13 @@ VarList *read_func_params() { if (consume(")")) { return NULL; } + + Token *tok = token; + if (consume("void") && consume(")")) { + return NULL; + } + token = tok; + VarList *head = read_func_param(); VarList *cur = head; @@ -562,7 +571,7 @@ VarList *read_func_params() { } // function = type-specifier declarator "(" params? ")" ("{" stmt* "}" | ";") -// params = param ("," param)* +// params = param ("," param)* | "void" // param = type-specifier declarator type-suffix Function *function() { locals = NULL; @@ -579,6 +588,7 @@ Function *function() { // construct a function object Function *fn = calloc(1, sizeof(Function)); fn->name = name; + fn->is_static = ty->is_static; expect("("); fn->params = read_func_params(); @@ -601,19 +611,6 @@ Function *function() { return fn; } -// global_var = type-specifier declarator type-suffix ";" -void global_var() { - Type *ty = type_specifier(); - char *name = NULL; - Token *tok = token; - ty = declarator(ty, &name); - ty = type_suffix(ty); - expect(";"); - - Var *var = push_var(name, ty, false, tok); - push_scope(name)->var = var; -} - // Initializer list can end either with "}" or "," followed by "}" to allow a // trailing comm. This function returns true if it looks like we are at the end // of an initializer list @@ -624,20 +621,180 @@ bool peek_end() { return ret; } -void expect_end() { +bool consume_end() { Token *tok = token; - if (consume(",") && consume("}")) { - return; + if (consume("}") || consume(",") && consume("}")) { + return true; } token = tok; expect("}"); + return false; +} + +void skip_excess_elements2() { + for (;;) { + if (consume("{")) { + skip_excess_elements2(); + } else { + assign(); + } + if (consume_end()) { + return; + } + expect(","); + } +} + +void skip_excess_elements() { + expect(","); + warn_tok(token, "excess elements in initalizer"); + skip_excess_elements2(); +} + +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; +} + +Initializer *new_init_label(Initializer *cur, char *label, long addend) { + Initializer *init = calloc(1, sizeof(Initializer)); + init->label = label; + init->addend = addend; + cur->next = init; + return init; +} + +Initializer *new_init_zero(Initializer *cur, int nbytes) { + for (int i = 0; i < nbytes; i++) { + cur = new_init_val(cur, 1, 0); + } + return cur; +} + +Initializer *gvar_init_string(char *p, int len) { + Initializer head; + head.next = NULL; + Initializer *cur = &head; + for (int i = 0; i < len; i++) { + cur = new_init_val(cur, 1, p[i]); + } + return head.next; +} + +Initializer *emit_struct_padding(Initializer *cur, Type *parent, Member *mem) { + int end = mem->offset + size_of(mem->ty, token); + + int padding; + if (mem->next) { + padding = mem->next->offset - end; + } else { + padding = size_of(parent, token) - end; + } + + if (padding) { + cur = new_init_zero(cur, padding); + } + return cur; +} + +Initializer *gvar_initializer(Initializer *cur, Type *ty) { + Token *tok = token; + if (ty->kind == TY_ARRAY && ty->base->kind == TY_CHAR && + token->kind == TK_STR) { + token = token->next; + if (ty->is_incomplete) { + ty->array_size = tok->cont_len; + ty->is_incomplete = false; + } + int len = (ty->array_size < tok->cont_len) ? ty->array_size : tok->cont_len; + for (int i = 0; i < len; i++) { + cur = new_init_val(cur, 1, tok->contents[i]); + } + return new_init_zero(cur, ty->array_size - len); + } + if (ty->kind == TY_ARRAY) { + bool open = consume("{"); + int i = 0; + int limit = ty->is_incomplete ? INT_MAX : ty->array_size; + do { + cur = gvar_initializer(cur, ty->base); + i++; + } while (i < limit && !peek_end() && consume(",")); + if (open && !consume_end()) { + skip_excess_elements(); + } + // Set excess array elements to zero. + cur = new_init_zero(cur, size_of(ty->base, tok) * (ty->array_size - i)); + if (ty->is_incomplete) { + ty->array_size = i; + ty->is_incomplete = false; + } + return cur; + } + if (ty->kind == TY_STRUCT) { + bool open = consume("{"); + Member *mem = ty->members; + do { + cur = gvar_initializer(cur, mem->ty); + cur = emit_struct_padding(cur, ty, mem); + mem = mem->next; + } while (mem && !peek_end() && consume(",")); + if (open && !consume_end()) { + skip_excess_elements(); + } + // Set excess struct elements to zero. + if (mem) { + int sz = size_of(ty, tok) - mem->offset; + if (sz) { + cur = new_init_zero(cur, sz); + } + } + return cur; + } + bool open = consume("{"); + Node *expr = conditional(); + if (open) { + expect("}"); + } + + Var *var = NULL; + long addend = eval2(expr, &var); + if (var) { + return new_init_label(cur, var->name, addend); + } + return new_init_val(cur, size_of(ty, token), addend); +} + +// global-var +// = type-specifier declarator type-suffix ("=" gvar-initializer)? ";" +void global_var() { + Type *ty = type_specifier(); + char *name = NULL; + Token *tok = token; + ty = declarator(ty, &name); + ty = type_suffix(ty); + + Var *var = push_var(name, ty, false, tok); + push_scope(name)->var = var; + + if (consume("=")) { + Initializer head; + head.next = NULL; + gvar_initializer(&head, ty); + var->initializer = head.next; + } + expect(";"); } typedef struct Designator Designator; struct Designator { Designator *next; - int idx; + int idx; // array + Member *mem; // struct }; // Creates a node for an array access. For example, if var represents next a @@ -650,6 +807,11 @@ Node *new_desg_node2(Var *var, Designator *desg) { } Node *node = new_desg_node2(var, desg->next); + if (desg->mem) { + node = new_unary(ND_MEMBER, node, desg->mem->tok); + node->member_name = desg->mem->name; + return node; + } node = new_binary(ND_ADD, node, new_num(desg->idx, tok), tok); return new_unary(ND_DEREF, node, tok); } @@ -660,6 +822,21 @@ Node *new_desg_node(Var *var, Designator *desg, Node *rhs) { return new_unary(ND_EXPR_STMT, node, rhs->tok); } +<<<<<<< HEAD +======= +Node *lvar_init_zero(Node *cur, Var *var, Type *ty, Designator *desg) { + if (ty->kind == TY_ARRAY) { + for (int i = 0; i < ty->array_size; i++) { + Designator desg2 = {desg, i++, NULL}; + cur = lvar_init_zero(cur, var, ty->base, &desg2); + } + return cur; + } + cur->next = new_desg_node(var, desg, new_num(0, token)); + return cur->next; +} + +>>>>>>> 7145500 (wip) // lvar-initializer = assign // | "{" lvar-initializer ("," lvar-initializer)* ","? "}" // An initializer for a local variable is expanded to multiple assignments. @@ -673,22 +850,118 @@ Node *new_desg_node(Var *var, Designator *desg, Node *rhs) { // x[1][0] = 4; // x[1][1] = 5; // x[1][2] = 6; +<<<<<<< HEAD +======= +// +// There are few special rules for ambiguous initalizers and shorthand +// notations: +// - if an initializer list is shorter than an array, excess array elements are +// initialized with 0 +<<<<<<< HEAD +<<<<<<< HEAD +>>>>>>> 7145500 (wip) +======= +// +// A char array can be initialized with a string literal. E.g., +// char x[4] = "foo" is equivalent to char x[4] = {'f', 'o', 'o', '\0'} +>>>>>>> 4765fbc (wip) +======= +// - a char array can be initialized with a string literal. E.g., +// char x[4] = "foo" is equivalent to char x[4] = {'f', 'o', 'o', '\0'} +// - if a rhs is an incomplete array, its size is set by counting the number of +// times on the rhs. E.g., +// x in int x[] = {1, 2, 3} has type int[3] +>>>>>>> 81ce31e (wip) Node *lvar_initializer(Node *cur, Var *var, Type *ty, Designator *desg) { - Token *tok = consume("{"); - if (!tok) { - cur->next = new_desg_node(var, desg, assign()); - return cur->next; + if (ty->kind == TY_ARRAY && ty->base->kind == TY_CHAR && + token->kind == TK_STR) { + // initialize a char array with a string literal + Token *tok = token; + token = token->next; + + if (ty->is_incomplete) { + ty->array_size = tok->cont_len; + ty->is_incomplete = false; + } + + int len = (ty->array_size < tok->cont_len) ? ty->array_size : tok->cont_len; + int i; + + for (i = 0; i < len; i++) { + Designator desg2 = {desg, i, NULL}; + Node *rhs = new_num(tok->contents[i], tok); + cur->next = new_desg_node(var, &desg2, rhs); + cur = cur->next; + } + + for (; i < ty->array_size; i++) { + Designator desg2 = {desg, i, NULL}; + cur = lvar_init_zero(cur, var, ty->base, &desg2); + } + return cur; } + if (ty->kind == TY_ARRAY) { + bool open = consume("{"); int i = 0; + int limit = ty->is_incomplete ? INT_MAX : ty->array_size; do { - Designator desg2 = {desg, i++}; + Designator desg2 = {desg, i++, NULL}; cur = lvar_initializer(cur, var, ty->base, &desg2); +<<<<<<< HEAD } while (!peek_end() && consume(",")); expect_end(); +<<<<<<< HEAD +======= + + // set excess array elemenets to zero +======= + } while (i < limit && !peek_end() && consume(",")); + if (open) consume_end(); + // set excessive array elements to zero +>>>>>>> 5279ec5 (wip) + while (i < ty->array_size) { + Designator desg2 = {desg, i++, NULL}; + cur = lvar_init_zero(cur, var, ty->base, &desg2); + } +<<<<<<< HEAD +<<<<<<< HEAD +>>>>>>> 7145500 (wip) +======= + +======= +>>>>>>> 5279ec5 (wip) + if (ty->is_incomplete) { + ty->array_size = i; + ty->is_incomplete = false; + } +>>>>>>> 81ce31e (wip) + return cur; + } + if (ty->kind == TY_STRUCT) { + bool open = consume("{"); + Member *mem = ty->members; + do { + Designator desg2 = {desg, 0, mem}; + cur = lvar_initializer(cur, var, mem->ty, &desg2); + mem = mem->next; + } while (mem && !peek_end() && consume(",")); + if (open && !consume_end()) { + skip_excess_elements(); + } + // set excessive struct elements to zero + for (; mem; mem = mem->next) { + Designator desg2 = {desg, 0, mem}; + cur = lvar_init_zero(cur, var, mem->ty, &desg2); + } return cur; } - error_tok(tok, "invalid array intializer"); + bool open = consume("{"); + cur->next = new_desg_node(var, desg, assign()); + if (open) { + expect("}"); + } + return cur->next; } // declaration @@ -907,12 +1180,18 @@ Node *expr() { return node; } -long eval(Node *node) { +long eval(Node *node) { eval2(node, NULL); } + +long eval2(Node *node, Var **var) { switch (node->kind) { - case ND_ADD: - return eval(node->lhs) + eval(node->rhs); - case ND_SUB: - return eval(node->lhs) - eval(node->rhs); + case ND_ADD: { + long lhs = eval2(node->lhs, var); + return lhs + eval2(node->rhs, var); + } + case ND_SUB: { + long lhs = eval2(node->lhs, var); + return lhs - eval2(node->rhs, var); + } case ND_MUL: return eval(node->lhs) * eval(node->rhs); case ND_DIV: @@ -949,6 +1228,18 @@ long eval(Node *node) { return eval(node->lhs) || eval(node->rhs); case ND_NUM: return node->val; + case ND_ADDR: + if (!var || *var || node->lhs->kind != ND_VAR) { + error_tok(node->tok, "invalid initializer"); + } + *var = node->lhs->var; + return 0; + case ND_VAR: + if (!var || *var || node->var->ty->kind != TY_ARRAY) { + error_tok(node->tok, "invalid initializer"); + } + *var = node->var; + return 0; } error_tok(node->tok, "not a constant expression"); } @@ -1312,8 +1603,7 @@ Node *primary() { Type *ty = array_of(char_type(), tok->cont_len); Var *var = push_var(new_label(), ty, false, NULL); - var->contents = tok->contents; - var->cont_len = tok->cont_len; + var->initializer = gvar_init_string(tok->contents, tok->cont_len); return new_var(var, tok); } if (tok->kind != TK_NUM) { diff --git a/tests b/tests index 082127b..120e68f 100644 --- a/tests +++ b/tests @@ -9,6 +9,33 @@ int g1; int g2[4]; +char g3 = 3; +short g4 = 4; +int g5 = 5; +long g6 = 6; +int *g7 = &g5; +char *g8 = "abc"; + +int g9[3] = {0, 1, 2}; +char *g10[] = {"foo", "bar"}; +struct {char a; int b;} g11[2] = {{1, 2}, {3, 4}}; +struct {int a[2];} g12[2] = {{{1, 2}}, {{3, 4}}}; + +struct {int a[2];} g13[2] = {{1, 2}, 3, 4}; +struct {int a[2];} g14[2] = {1, 2, 3, 4}; +char *g15 = {"foo"}; +char g16[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0}; + +char g17[] = "foobar"; +char g18[10] = "foobar"; +char g19[3] = "foobar"; + +char *g20 = g17+0; +char *g21 = g17+3; +char *g22 = g17-3; +int g23=3; +int *g24=&g23; + int assert(long expected, long actual, char *code) { if (expected == actual) { printf("%s => %ld\n", code, actual); @@ -62,7 +89,9 @@ int count() { int param_decay(int x[]) { return 0[x]; } -void voidfn() {} +void voidfn(void) {} + +static int static_fn(void) {} int main() { assert(8, ({ @@ -842,6 +871,113 @@ int main() { assert(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; }), "int x[2][3]={{1,2,3},{4,5,6}}; x[1][0];"); assert(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; }), "int x[2][3]={{1,2,3},{4,5,6}}; x[1][2];"); +<<<<<<< HEAD +======= + assert(2, ({ int x[2][3]={{1,2}}; x[0][1]; }), "int x[2][3]={{1,2}}; x[0][1];"); + assert(0, ({ int x[2][3]={{1,2}}; x[1][0]; }), "int x[2][3]={{1,2}}; x[1][0];"); + assert(0, ({ int x[2][3]={{1,2}}; x[1][2]; }), "int x[2][3]={{1,2}}; x[1][2];"); + +<<<<<<< HEAD +>>>>>>> 7145500 (wip) +======= + assert('a', ({ char x[4]="abc"; x[0]; }), "char x[4]=\"abc\"; x[0]; }"); + assert('c', ({ char x[4]="abc"; x[2]; }), "char x[4]=\"abc\"; x[2]; }"); + assert(0, ({ char x[4]="abc"; x[3]; }), "char x[4]=\"abc\"; x[3]; }"); + assert('a', ({ char x[2][4]={"abc","def"}; x[0][0]; }), "char x[2][4]=\"abc\",\"def\"}; x[0][0]; }"); + assert(0, ({ char x[2][4]={"abc","def"}; x[0][3]; }), "char x[2][4]=\"abc\",\"def\"}; x[0][3]; }"); + assert('d', ({ char x[2][4]={"abc","def"}; x[1][0]; }), "char x[2][4]=\"abc\",\"def\"}; x[1][0]; }"); + assert('f', ({ char x[2][4]={"abc","def"}; x[1][2]; }), "char x[2][4]=\"abc\",\"def\"}; x[1][2]; }"); + +<<<<<<< HEAD +>>>>>>> 4765fbc (wip) +======= + assert(4, ({ int x[]={1,2,3,4}; x[3]; }), "int x[]={1,2,3,4}; x[3];"); + assert(16, ({ int x[]={1,2,3,4}; sizeof(x); }), "int x[]={1,2,3,4}; sizeof(x);"); + assert(4, ({ char x[]="foo"; sizeof(x); }), "char x[]=\"foo\"; sizeof(x); }"); + +<<<<<<< HEAD +>>>>>>> 81ce31e (wip) +======= + assert(1, ({ struct {int a; int b; int c;} x={1,2,3}; x.a; }), "struct {int a; int b; int c;} x={1,2,3}; x.a;"); + assert(2, ({ struct {int a; int b; int c;} x={1,2,3}; x.b; }), "struct {int a; int b; int c;} x={1,2,3}; x.b;"); + assert(3, ({ struct {int a; int b; int c;} x={1,2,3}; x.c; }), "struct {int a; int b; int c;} x={1,2,3}; x.c;"); + assert(1, ({ struct {int a; int b; int c;} x={1}; x.a; }), "struct {int a; int b; int c;} x={1}; x.a;"); + assert(0, ({ struct {int a; int b; int c;} x={1}; x.b; }), "struct {int a; int b; int c;} x={1}; x.b;"); + assert(0, ({ struct {int a; int b; int c;} x={1}; x.c; }), "struct {int a; int b; int c;} x={1}; x.c;"); + assert(1, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a; }), "struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a;"); + assert(2, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b; }), "struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b;"); + assert(3, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a; }), "struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a;"); + assert(4, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b; }), "struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b;"); + assert(0, ({ struct {int a; int b;} x[2]={{1,2}}; x[1].b; }), "struct {int a; int b;} x[2]={{1,2}}; x[1].b;"); + +<<<<<<< HEAD +>>>>>>> 0726817 (wip) +======= + 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\")"); + +<<<<<<< HEAD +>>>>>>> c7b736a (wip) +======= + assert(0, g9[0], "g9[0]"); + assert(1, g9[1], "g9[1]"); + assert(2, g9[2], "g9[2]"); + assert(0, strcmp(g10[0], "foo"), "strcmp(g10[0], \"foo\")"); + assert(0, strcmp(g10[1], "bar"), "strcmp(g10[1], \"bar\")"); + assert(0, g10[1][3], "g10[1][3]"); + assert(2, sizeof(g10) / sizeof(*g10), "sizeof(g10) / sizeof(*g10)"); + assert(1, g11[0].a, "g11[0].a"); + assert(2, g11[0].b, "g11[0].b"); + assert(3, g11[1].a, "g11[1].a"); + assert(4, g11[1].b, "g11[1].b"); + assert(1, g12[0].a[0], "g12[0].a[0]"); + assert(2, g12[0].a[1], "g12[0].a[1]"); + assert(3, g12[1].a[0], "g12[1].a[0]"); + assert(4, g12[1].a[1], "g12[1].a[1]"); + +<<<<<<< HEAD +>>>>>>> e95cc8b (wip) +======= + assert(1, g13[0].a[0], "g13[0].a[0]"); + assert(2, g13[0].a[1], "g13[0].a[1]"); + assert(3, g13[1].a[0], "g13[1].a[0]"); + assert(4, g13[1].a[1], "g13[1].a[1]"); + assert(1, g14[0].a[0], "g14[0].a[0]"); + assert(2, g14[0].a[1], "g14[0].a[1]"); + assert(3, g14[1].a[0], "g14[1].a[0]"); + assert(4, g14[1].a[1], "g14[1].a[1]"); + assert(0, ({ int x[2][3]={0,1,2,3,4,5,}; x[0][0]; }), "int x[2][3]={0,1,2,3,4,5,}; x[0][0];"); + assert(3, ({ int x[2][3]={0,1,2,3,4,5,}; x[1][0]; }), "int x[2][3]={0,1,2,3,4,5,}; x[1][0];"); + assert(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; }), "struct {int a; int b;} x[2]={0,1,2,3}; x[0].a;"); + assert(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; }), "struct {int a; int b;} x[2]={0,1,2,3}; x[1].a;"); + assert(0, strcmp(g15, "foo"), "strcmp(g15, \"foo\")"); + assert(0, strcmp(g16[0], "foo"), "strcmp(g16[0], \"foo\")"); + assert(0, strcmp(g16[1], "bar"), "strcmp(g16[1], \"bar\")"); + +<<<<<<< HEAD +>>>>>>> 5279ec5 (wip) +======= + assert(7, sizeof(g17), "sizeof(g17)"); + assert(10, sizeof(g18), "sizeof(g18)"); + assert(3, sizeof(g19), "sizeof(g19)"); + assert(0, memcmp(g17, "foobar", 7), "memcmp(g17, \"foobar\", 7)"); + assert(0, memcmp(g18, "foobar\0\0\0", 10), "memcmp(g18, \"foobar\\0\\0\\0\", 10)"); + assert(0, memcmp(g19, "foo", 3), "memcmp(g19, \"foo\", 3)"); + +<<<<<<< HEAD +>>>>>>> e41a858 (wip) +======= + assert(0, strcmp(g20, "foobar"), "strcmp(g20, \"foobar\")"); + assert(0, strcmp(g21, "bar"), "strcmp(g21, \"bar\")"); + assert(0, strcmp(g22+3, "foobar"), "strcmp(g22+3, \"foobar\")"); + assert(3, g23, "g23"); + assert(3, *g24, "*g24"); + +>>>>>>> 476fdf4 (wip) printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index 688c912..4cb3dda 100644 --- a/tokenize.c +++ b/tokenize.c @@ -44,7 +44,6 @@ void verror_at(char *loc, char *fmt, va_list ap) { fprintf(stderr, "^ "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); - exit(1); } // Reports an error location and exit. @@ -52,6 +51,7 @@ void error_at(char *loc, char *fmt, ...) { va_list ap; va_start(ap, fmt); verror_at(loc, fmt, ap); + exit(1); } // Reports an error location and exit. @@ -60,12 +60,24 @@ void error_tok(Token *tok, char *fmt, ...) { va_start(ap, fmt); if (tok) { verror_at(tok->str, fmt, ap); + } else { + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); } - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); exit(1); } +void warn_tok(Token *tok, char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + if (tok) { + verror_at(tok->str, fmt, ap); + } else { + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } +} + char *strndup(char *p, int len) { char *buf = malloc(len + 1); strncpy(buf, p, len);