scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 4730c12530c7db4e61d812e9f45d631d7bc1bdfe
parent 1f34f795dd1fab4c3246623af6c8a095a5ffe634
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Thu, 10 Sep 2015 18:16:05 +0200

Add initializer to static objects

Static objects cannot be initialized by assignations, so we need define
the initializer with other syntax.

Diffstat:
Mcc1/cc1.h | 3++-
Mcc1/code.c | 20++++++++++++++++----
Mcc1/decl.c | 5++---
Mcc1/expr.c | 46++++++++++++++++++++++++++++++++++------------
4 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -158,7 +158,8 @@ enum { ISLOCAL = 512, ISEMITTED = 1024, ISDEFINED = 2048, - ISSTRING = 4096 + ISSTRING = 4096, + ISTYPEDEF = 8192 }; diff --git a/cc1/code.c b/cc1/code.c @@ -16,7 +16,8 @@ static void emitbin(unsigned, void *), emitsymid(unsigned, void *), emittext(unsigned, void *), emitfun(unsigned, void *), - emitdcl(unsigned, void *); + emitdcl(unsigned, void *), + emitinit(unsigned, void *); char *optxt[] = { [OADD] = "+", @@ -39,7 +40,6 @@ char *optxt[] = { [OBXOR] = "^", [OBOR] = "|", [OASSIGN] = ":", - [OINIT] = ":", [OA_MUL] = ":*", [OA_DIV] = ":/", [OA_MOD] = ":%", @@ -92,7 +92,6 @@ void (*opcode[])(unsigned, void *) = { [OBXOR] = emitbin, [OBOR] = emitbin, [OASSIGN] = emitbin, - [OINIT] = emitbin, [OA_MUL] = emitbin, [OA_DIV] = emitbin, [OA_MOD] = emitbin, @@ -129,7 +128,8 @@ void (*opcode[])(unsigned, void *) = { [OSWITCH] = emitswitch, [OSWITCHT] = emitswitcht, [OPAR] = emitbin, - [OCALL] = emitbin + [OCALL] = emitbin, + [OINIT] = emitinit }; void @@ -284,6 +284,18 @@ emittype(Type *tp) } static void +emitinit(unsigned op, void *arg) +{ + Node *np = arg; + + puts("("); + emitexp(OEXPR, np->right); + puts(")"); + np->right = NULL; + freetree(np); +} + +static void emitdcl(unsigned op, void *arg) { Symbol *sym = arg; diff --git a/cc1/decl.c b/cc1/decl.c @@ -661,6 +661,7 @@ identifier(struct decl *dcl) flags |= (curctx == GLOBALCTX) ? ISPRIVATE : ISLOCAL; break; case TYPEDEF: + flags |= ISTYPEDEF; sym->token = TYPEIDEN; break; } @@ -668,8 +669,6 @@ identifier(struct decl *dcl) } /* TODO: disallow initializators in functions */ - /* TODO: check if typedef has initializer */ - /* TODO: check if the variable is extern and has initializer */ if (sym->token == IDEN && sym->type->op != FTN) emit(ODECL, sym); if (accept('=')) @@ -732,7 +731,7 @@ decl(void) case TYPE: case TQUALIFIER: case SCLASS: - if (sym->token == TYPEIDEN) + if (sym->flags & ISTYPEDEF) errorp("function definition declared 'typedef'"); if (sym->flags & ISDEFINED) errorp("redefinition of '%s'", sym->name); diff --git a/cc1/expr.c b/cc1/expr.c @@ -980,24 +980,46 @@ condexpr(void) /* TODO: check correctness of the initializator */ /* TODO: emit initializer */ +static void +initlist(void) +{ + Node *np; + + if (yytoken == '}') + return; + + do { + if (accept('{')) + initlist(); + assign(); + } while (accept(',')); + + expect('}'); +} + void initializer(Symbol *sym) { Node *np; + int flags = sym->flags; if (accept('{')) { - do { - if (yytoken == '}') - break; - initializer(sym); - } while (accept(',')); - - expect('}'); - return; - } - np = expr(); - if ((sym->flags & ISLOCAL) == 0) { - emit(OEXPR, assignop(OINIT, varnode(sym), np)); + initlist(); return; } + np = assignop(OINIT, varnode(sym), assign()); + + if ((flags & (ISLOCAL|ISPRIVATE|ISGLOBAL)) != 0) { + if (!np->right->constant) + errorp("initializer element is not constant"); + emit(OINIT, np); + } else if ((flags & (ISEXTERN|ISTYPEDEF)) != 0) { + errorp("'%s' has both '%s' and initializer", + sym->name, (flags&ISEXTERN) ? "extern" : "typedef"); + } else if (flags & ISFIELD) { + ; + } else { + np->op = OASSIGN; + emit(OEXPR, np); + } }