[hackers] [scc] Second rewritten of decl.c || Roberto E. Vargas Caballero

From: <git_AT_suckless.org>
Date: Mon, 10 Aug 2015 17:36:47 +0200 (CEST)

commit b45fa07261e9c67a83dd910dfcfc44a3d8c41d1e
Author: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
AuthorDate: Mon Aug 10 17:34:04 2015 +0200
Commit: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
CommitDate: Mon Aug 10 17:34:04 2015 +0200

    Second rewritten of decl.c
    
    This rewritten add the semantic for symbol linkage.

diff --git a/cc1/TODO b/cc1/TODO
index 96638cb..d189767 100644
--- a/cc1/TODO
+++ b/cc1/TODO
_AT_@ -1,7 +1,6 @@
 * Verify correctness in initializators
 * emit initializators
 * emit structures definition
-* Allow external declarations of incomplete array types
 * Implement bitfields
 * Define data structure shared between cc1 and cc2 with the type
   information
_AT_@ -11,3 +10,5 @@
 * Parse correctly all integer and float constants
 * Add C99 features (almost all the new features of C99 are missed)
 * Add correct emit for any kind of constant
+* Add warnings in overflow of contant operations
+* Add warning when some ANSI limit is violated.
diff --git a/cc1/cc1.h b/cc1/cc1.h
index 4506a6c..ee724f9 100644
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
_AT_@ -109,7 +109,7 @@ enum {
         FTN = 1,
         PTR,
         ARY,
- PARS,
+ PARS
 };
 
 /* namespaces */
_AT_@ -125,17 +125,18 @@ enum {
 
 /* symbol flags */
 enum {
- ISSTATIC = 1,
- ISAUTO = 2,
- ISREGISTER = 4,
- ISDEFINED = 8,
- ISFIELD = 16,
- ISEXTERN = 32,
- ISUSED = 64,
- ISCONSTANT = 128,
- ISGLOBAL = 256,
- ISPRIVATE = 512,
- ISLOCAL = 1024
+ ISAUTO = 1,
+ ISREGISTER = 2,
+ ISDECLARED = 4,
+ ISFIELD = 8,
+ ISEXTERN = 16,
+ ISUSED = 32,
+ ISCONSTANT = 64,
+ ISGLOBAL = 128,
+ ISPRIVATE = 256,
+ ISLOCAL = 512,
+ ISEMITTED = 1024,
+ ISDEFINED = 2048
 };
 
 
diff --git a/cc1/code.c b/cc1/code.c
index 2403f52..78a3517 100644
--- a/cc1/code.c
+++ b/cc1/code.c
_AT_@ -163,6 +163,8 @@ emitvar(Symbol *sym)
                 c = L_REGISTER;
         else if (flags & ISFIELD)
                 c = L_FIELD;
+ else if (flags & ISEXTERN)
+ c = L_EXTERN;
         else
                 c = L_AUTO;
         printf("%c%d", c, sym->id);
_AT_@ -222,6 +224,7 @@ emittype(Type *tp)
 
         if (tp->printed)
                 return;
+ tp->printed = 1;
 
         switch (tp->op) {
         case ARY:
_AT_@ -253,12 +256,15 @@ emitdcl(unsigned op, void *arg)
 {
         Symbol *sym = arg;
 
+ if (sym->flags & ISEMITTED)
+ return;
         emittype(sym->type);
         emitvar(sym);
         putchar('\t');
         emitletter(sym->type);
         if (op != OFUN)
                 putchar('\n');
+ sym->flags |= ISEMITTED;
 }
 
 static void
diff --git a/cc1/cpp.c b/cc1/cpp.c
index 3080dee..98765b0 100644
--- a/cc1/cpp.c
+++ b/cc1/cpp.c
_AT_@ -30,7 +30,7 @@ defmacro(char *s)
 
         strcpy(yytext, s);
         sym = lookup(NS_CPP);
- sym->flags |= ISDEFINED;
+ sym->flags |= ISDECLARED;
         return sym;
 }
 
_AT_@ -326,13 +326,13 @@ define(void)
         if (yytoken != IDEN)
                 error("macro names must be identifiers");
         sym = yylval.sym;
- if ((sym->flags & ISDEFINED) && sym->ns == NS_CPP) {
+ if ((sym->flags & ISDECLARED) && sym->ns == NS_CPP) {
                 warn("'%s' redefined", yytext);
                 free(sym->u.s);
         } else if (sym->ns != NS_CPP) {
                 sym = lookup(NS_CPP);
         }
- sym->flags |= ISDEFINED;
+ sym->flags |= ISDECLARED;
 
         pushctx();
 
_AT_@ -469,7 +469,7 @@ ifclause(int negate, int isifdef)
                 }
                 sym = lookup(NS_CPP);
                 next();
- status = (sym->flags & ISDEFINED) != 0;
+ status = (sym->flags & ISDECLARED) != 0;
         } else {
                 if ((expr = iconstexpr()) == NULL)
                         error("parameter of #if is not an integer constant expression");
_AT_@ -540,7 +540,7 @@ undef(void)
                 return;
         }
         sym = lookup(NS_CPP);
- sym->flags &= ~ISDEFINED;
+ sym->flags &= ~ISDECLARED;
         next();
 }
 
diff --git a/cc1/decl.c b/cc1/decl.c
index e783615..a628763 100644
--- a/cc1/decl.c
+++ b/cc1/decl.c
_AT_@ -2,12 +2,16 @@
 #include <inttypes.h>
 #include <setjmp.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "../inc/sizes.h"
 #include "../inc/cc.h"
 #include "cc1.h"
 
+#define GLOBALCTX 0
+#define NOSCLASS 0
+
 struct dcldata {
         unsigned char op;
         unsigned short nelem;
_AT_@ -49,40 +53,65 @@ arydcl(struct dcldata *dp)
         return queue(dp, ARY, n, NULL);
 }
 
-static void
-parameter(Symbol *sym, int sclass, Type *data)
+static Symbol *
+parameter(Symbol *sym, Type *tp, unsigned ns, int sclass, Type *data)
 {
- Type *tp = sym->type, *funtp = data;
+ Type *funtp = data;
         size_t n = funtp->n.elem;
+ char *name = sym->name;
 
- if (tp == voidtype) {
- if (n != 0)
- error("incorrect void parameter");
- funtp->n.elem = -1;
- return;
- }
+ sym->type = tp;
 
         if (n == -1)
                 error("'void' must be the only parameter");
- tp = sym->type;
- if (tp->op == FTN)
- error("incorrect function type for a function parameter");
- if (tp->op == ARY)
- tp = mktype(tp->type, PTR, 0, NULL);
- if (sym->flags & (ISSTATIC|ISEXTERN|ISAUTO))
+
+ switch (sclass) {
+ case STATIC:
+ case EXTERN:
+ case AUTO:
                 error("bad storage class in function parameter");
- if (!sclass)
+ case REGISTER:
+ sym->flags |= ISREGISTER;
+ break;
+ case NOSCLASS:
                 sym->flags |= ISAUTO;
+ break;
+ }
+
+ switch (tp->op) {
+ case VOID:
+ if (n != 0)
+ error("incorrect void parameter");
+ if (sclass)
+ error("void as unique parameter may not be qualified");
+ funtp->n.elem = -1;
+ return NULL;
+ case ARY:
+ tp = mktype(tp->type, PTR, 0, NULL);
+ break;
+ case FTN:
+ error("incorrect function type for a function parameter");
+ }
+
+ if (name) {
+ if ((sym = install(NS_IDEN, sym)) == NULL)
+ error("redefinition of parameter '%s'", name);
+ }
+ sym->type = tp;
+
         if (n++ == NR_FUNPARAM)
                 error("too much parameters in function definition");
         funtp->pars = xrealloc(funtp->pars, n * sizeof(Type *));
         funtp->pars[n-1] = tp;
         funtp->n.elem = n;
+
+ return sym;
 }
 
 static Symbol *dodcl(int rep,
- void (*fun)(Symbol *, int, Type *),
- uint8_t ns, Type *type);
+ Symbol *(*fun)(Symbol *, Type *, unsigned, int, Type *),
+ unsigned ns,
+ Type *type);
 
 static struct dcldata *
 fundcl(struct dcldata *dp)
_AT_@ -114,18 +143,6 @@ fundcl(struct dcldata *dp)
                 }
         }
 
- switch (yytoken) {
- default:
- /* This is not a function */
- popctx();
- case '{':
- case TYPEIDEN:
- case TYPE:
- case TQUALIFIER:
- case SCLASS:
- /* This can be a function (K&R included) */
- break;
- }
         return dp;
 }
 
_AT_@ -177,7 +194,7 @@ declarator0(struct dcldata *dp, unsigned ns)
 }
 
 static Symbol *
-declarator(Type *tp, unsigned ns, int sclass)
+declarator(Type *tp, unsigned ns, Type **otp)
 {
         struct dcldata data[NR_DECLARATORS+1];
         struct dcldata *bp;
_AT_@ -198,26 +215,11 @@ declarator(Type *tp, unsigned ns, int sclass)
                         break;
                 }
         }
-
- if ((name = sym->name) == NULL) {
- sym->type = tp;
- } else {
- short flags;
-
- if ((sym = install(ns, osym = sym)) == NULL) {
- if (!eqtype(osym->type, tp))
- error("conflicting types for '%s'", name);
- sym = osym;
- } else {
- sym->u.pars = pars;
- sym->type = tp;
- }
- if (!tp->defined && sclass != EXTERN) {
- error("declared variable '%s' of incomplete type",
- name);
- }
- }
-
+ /*
+ * FIXME: This assignation can destroy pars of a previous definition
+ */
+ sym->u.pars = pars;
+ *otp = tp;
         return sym;
 }
 
_AT_@ -343,7 +345,7 @@ newtag(void)
         case IDEN:
         case TYPEIDEN:
                 sym = yylval.sym;
- if ((sym->flags & ISDEFINED) == 0)
+ if ((sym->flags & ISDECLARED) == 0)
                         install(NS_TAG, yylval.sym);
                 next();
                 break;
_AT_@ -429,123 +431,191 @@ enumdcl(void)
         return tp;
 }
 
-static void
-type(Symbol *sym, int sclass, Type *data)
+static Symbol *
+type(Symbol *sym, Type *tp, unsigned ns, int sclass, Type *data)
 {
         if (sclass)
                 error("class storage in type name");
         if (sym->name)
                 error("unexpected identifier in type name");
+ sym->type = tp;
+
+ return sym;
 }
 
-static void
-field(Symbol *sym, int sclass, Type *data)
+static Symbol *
+field(Symbol *sym, Type *tp, unsigned ns, int sclass, Type *data)
 {
- Type *tp = sym->type, *funtp = data;
+ Type *funtp = data;
         size_t n = funtp->n.elem;
+ char *name = sym->name;
 
         if (sclass)
                 error("storage class in struct/union field");
         if (!sym->name)
                 error("missed identifier in field declaration");
+
         if (tp->op == FTN)
                 error("invalid type in struct/union");
+ if (!tp->defined)
+ error("field '%s' has incomplete type", name);
+
+ if ((sym = install(ns, sym)) == NULL)
+ error("duplicated member '%s'", name);
+ sym->type = tp;
+
         sym->flags |= ISFIELD;
         if (n++ == NR_FUNPARAM)
                 error("too much fields in struct/union");
         funtp->pars = xrealloc(funtp->pars, n);
         funtp->pars[n-1] = tp;
         funtp->n.elem = n;
+
+ return sym;
 }
 
-static void
-internal(Symbol *sym, int sclass, Type *data)
+static Symbol *
+identifier(Symbol *sym, Type *tp, unsigned ns, int sclass, Type *data)
 {
- if (!sym->name) {
+ char *name = sym->name;
+ short flags;
+ Symbol *osym;
+
+ if (!name) {
+ sym->type = tp;
                 warn("empty declaration");
- return;
+ return sym;
         }
- if (sym->type->op != FTN) {
- if (!sclass)
- sym->flags |= ISAUTO;
- if (accept('='))
- initializer(sym);
- /* TODO: check if the variable is extern and has initializer */
- }
- if (sym->flags & ISSTATIC)
- sym->flags |= ISLOCAL;
- emit(ODECL, sym);
-}
 
-static void
-external(Symbol *sym, int sclass, Type *data)
-{
- if (!sym->name) {
- warn("empty declaration");
- return;
+ /* TODO: Add warning about ANSI limits */
+ if (!tp->defined && sclass != EXTERN)
+ error("declared variable '%s' of incomplete type", name);
+
+ if (tp->op == FTN) {
+ if (sclass == NOSCLASS)
+ sclass = EXTERN;
+ /*
+ * FIXME: Ugly workaround to solve function declarations.
+ * A new context is added for the parameters,
+ * so at this point curctx is incremented by
+ * one when sym was parsed.
+ * It can destroy the order of the hash when
+ * there is a previous declaration in an outer contex.
+ */
+ --curctx;
+ sym = install(NS_IDEN, sym);
+ ++curctx;
+ } else {
+ sym = install(NS_IDEN, osym = sym);
         }
 
- if (sym->flags & (ISREGISTER|ISAUTO))
- error("incorrect storage class for file-scope declaration");
- sym->flags |= (sym->flags & ISSTATIC) ? ISPRIVATE : ISGLOBAL;
-
- if (sym->type->op == FTN && yytoken == '{') {
- if (sym->token == TYPEIDEN)
- error("function definition declared 'typedef'");
- curfun = sym;
- sym->flags |= ISDEFINED;
- emit(OFUN, sym);
- compound(NULL, NULL, NULL);
- emit(OEFUN, NULL);
- return;
+ if (sym == NULL) {
+ sym = osym;
+ flags = sym->flags;
+ if (!eqtype(sym->type, tp))
+ error("conflicting types for '%s'", name);
+ if (sym->token == TYPEIDEN && sclass != TYPEDEF ||
+ sym->token != TYPEIDEN && sclass == TYPEDEF)
+ goto redeclaration;
+
+ if (curctx != GLOBALCTX && tp->op != FTN) {
+ if (!(sym->flags & ISEXTERN) || sclass != EXTERN)
+ goto redeclaration;
+ } else {
+ switch (sclass) {
+ case REGISTER:
+ case AUTO:
+ goto bad_storage;
+ case NOSCLASS:
+ if (flags & ISPRIVATE)
+ goto non_after_static;
+ flags &= ~ISEXTERN;
+ flags |= ISGLOBAL;
+ case TYPEDEF:
+ case EXTERN:
+ break;
+ case STATIC:
+ if (flags & (ISGLOBAL|ISEXTERN))
+ goto static_after_non;
+ flags |= ISPRIVATE;
+ break;
+ }
+ }
+ } else {
+ flags = sym->flags;
+ switch (sclass) {
+ case REGISTER:
+ case AUTO:
+ if (curctx == GLOBALCTX || tp->op == FTN)
+ goto bad_storage;
+ flags |= (sclass == REGISTER) ? ISREGISTER : ISAUTO;
+ break;
+ case NOSCLASS:
+ flags |= (curctx == GLOBALCTX) ? ISGLOBAL : ISAUTO;
+ break;
+ case EXTERN:
+ flags |= ISEXTERN;
+ break;
+ case STATIC:
+ flags |= (curctx == GLOBALCTX) ? ISPRIVATE : ISLOCAL;
+ break;
+ case TYPEDEF:
+ sym->token = TYPEIDEN;
+ break;
+ }
         }
+
+ sym->flags = flags;
+ sym->type = tp;
+
         if (accept('='))
                 initializer(sym);
+ /* TODO: disallow initializators in functions */
+ /* TODO: check if typedef has initializer */
         /* TODO: check if the variable is extern and has initializer */
- emit(ODECL, sym);
+ if (sym->token == IDEN)
+ emit(ODECL, sym);
+ return sym;
+
+redeclaration:
+ error("redeclaration of '%s'", name);
+
+bad_storage:
+ if (tp->op != FTN)
+ error("incorrect storage class for file-scope declaration");
+bad_function:
+ error("invalid storage class for function '%s'", name);
+
+non_after_static:
+ error("non-static declaration of '%s' follows static declaration",
+ name);
+
+static_after_non:
+ error("static declaration of '%s' follows non-static declaration",
+ name);
 }
 
 static Symbol *
-dodcl(int rep, void (*fun)(Symbol *, int, Type *), uint8_t ns, Type *type)
+dodcl(int rep,
+ Symbol *(*fun)(Symbol *, Type *, unsigned, int, Type *),
+ unsigned ns,
+ Type *data)
 {
         Symbol *sym;
         Type *base, *tp;
         int sclass;
 
         if ((base = specifier(&sclass)) == NULL) {
- if (curctx != 0)
+ if (curctx != GLOBALCTX)
                         unexpected();
                 warn("type defaults to 'int' in declaration");
                 base = inttype;
         }
 
         do {
- sym = declarator(base, ns, sclass);
- tp = sym->type;
-
- switch (sclass) {
- case REGISTER:
- sym->flags |= ISREGISTER;
- break;
- case AUTO:
- sym->flags |= ISAUTO;
- break;
- case STATIC:
- sym->flags |= ISSTATIC;
- break;
- case EXTERN:
- sym->flags |= ISEXTERN;
- break;
- case TYPEDEF:
- sym->token = TYPEIDEN;
- break;
- }
- if (tp->op == FTN && (sym->flags & (ISREGISTER|ISAUTO))) {
- error("invalid storage class for function '%s'",
- sym->name);
- }
- (*fun)(sym, sclass, type);
- } while (rep && !curfun && accept(','));
+ sym = declarator(base, ns, &tp);
+ sym = (*fun)(sym, tp, ns, sclass, data);
+ } while (rep && accept(','));
 
         return sym;
 }
_AT_@ -553,14 +623,45 @@ dodcl(int rep, void (*fun)(Symbol *, int, Type *), uint8_t ns, Type *type)
 void
 decl(void)
 {
+ Symbol *sym;
+
         if (accept(';'))
                 return;
- if (!dodcl(1, (curctx == 0) ? external : internal, NS_IDEN, NULL))
- return;
- if (curfun)
- curfun == NULL;
- else
- expect(';');
+ sym = dodcl(1, identifier, NS_IDEN, NULL);
+
+ /*
+ * Functions only can appear at global context,
+ * but due to parameter context, we have to check
+ * against GLOBALCTX+1
+ */
+ if (sym->type->op == FTN && curctx == GLOBALCTX+1) {
+ switch (yytoken) {
+ case '{':
+ case TYPEIDEN:
+ case TYPE:
+ case TQUALIFIER:
+ case SCLASS:
+ if (sym->token == TYPEIDEN)
+ error("function definition declared 'typedef'");
+ if (sym->flags & ISDEFINED)
+ error("redefinition of '%s'", sym->name);
+ if (sym->flags & ISEXTERN) {
+ sym->flags &= ~ISEXTERN;
+ sym->flags |= ISGLOBAL;
+ }
+ sym->flags |= ISDEFINED;
+ sym->flags &= ~ISEMITTED;
+ curfun = sym;
+ emit(OFUN, sym);
+ compound(NULL, NULL, NULL);
+ emit(OEFUN, NULL);
+ curfun = NULL;
+ return;
+ default:
+ popctx();
+ }
+ }
+ expect(';');
 }
 
 static void
diff --git a/cc1/error.c b/cc1/error.c
index d42e190..9c6c7ea 100644
--- a/cc1/error.c
+++ b/cc1/error.c
_AT_@ -51,6 +51,7 @@ error(char *fmt, ...)
         va_start(va, fmt);
         warn_helper(-1, fmt, va);
         va_end(va);
+ exit(1);
         discard();
 }
 
diff --git a/cc1/expr.c b/cc1/expr.c
index 875364f..3c29934 100644
--- a/cc1/expr.c
+++ b/cc1/expr.c
_AT_@ -721,9 +721,9 @@ primary(void)
                 next();
                 break;
         case IDEN:
- if (!(yylval.sym->flags & ISDEFINED)) {
+ if (!(yylval.sym->flags & ISDECLARED)) {
                         yylval.sym->type = inttype;
- yylval.sym->flags |= ISDEFINED;
+ yylval.sym->flags |= ISDECLARED;
                         error("'%s' undeclared", yytext);
                 }
                 yylval.sym->flags |= ISUSED;
diff --git a/cc1/stmt.c b/cc1/stmt.c
index 377f520..7a8081f 100644
--- a/cc1/stmt.c
+++ b/cc1/stmt.c
_AT_@ -28,9 +28,9 @@ label(void)
                  * an undefined symbol that is not going to be used ever.
                  */
                 sym = lookup(NS_LABEL);
- if (sym->flags & ISDEFINED)
+ if (sym->flags & ISDECLARED)
                         error("label '%s' already defined", yytoken);
- sym->flags |= ISDEFINED;
+ sym->flags |= ISDECLARED;
                 emit(OLABEL, sym);
                 next();
                 expect(':');
diff --git a/cc1/symbol.c b/cc1/symbol.c
index 4b25f16..a35f08e 100644
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
_AT_@ -67,7 +67,7 @@ popctx(void)
                 case NS_LABEL:
                         if (curctx != 0)
                                 goto save_symbol;
- if (sym->flags & ISDEFINED)
+ if (sym->flags & ISDECLARED)
                                 break;
                         printerr("label '%s' is not defined", sym->name);
                         break;
_AT_@ -87,10 +87,12 @@ popctx(void)
                 if (sym->name) {
                         short f = sym->flags;
                         htab[hash(sym->name)] = sym->hash;
- if ((f & (ISUSED|ISGLOBAL|ISDEFINED)) == ISDEFINED)
+ if ((f & (ISUSED|ISGLOBAL|ISDECLARED)) == ISDECLARED)
                                 warn("'%s' defined but not used", sym->name);
                 }
                 free(sym->name);
+ if (sym->type && sym->type->op == FTN)
+ free(sym->u.pars);
                 free(sym);
         }
         hp->next = sym;
_AT_@ -103,8 +105,7 @@ duptype(Type *base)
         Type *tp = xmalloc(sizeof(*tp));
 
         *tp = *base;
- if (tp->op == ARY)
- tp->id = (curctx) ? ++localcnt : ++globalcnt;
+ tp->id = (curctx) ? ++localcnt : ++globalcnt;
         return tp;
 }
 
_AT_@ -118,7 +119,7 @@ newsym(unsigned ns)
         sym->ns = ns;
         sym->ctx = curctx;
         sym->token = IDEN;
- sym->flags = ISDEFINED;
+ sym->flags = ISDECLARED;
         sym->name = NULL;
         sym->type = NULL;
         sym->hash = NULL;
_AT_@ -178,7 +179,7 @@ nextsym(Symbol *sym, unsigned ns)
                         return sym;
         }
         new = newsym(ns);
- new->flags &= ~ISDEFINED;
+ new->flags &= ~ISDECLARED;
         new->name = xstrdup(yytext);
         new->hash = sym->hash;
         return sym->hash = new;
_AT_@ -188,16 +189,16 @@ Symbol *
 install(unsigned ns, Symbol *sym)
 {
         if (sym->ctx == curctx) {
- if (sym->flags & ISDEFINED)
+ if (sym->flags & ISDECLARED)
                         return NULL;
- sym->flags |= ISDEFINED;
+ sym->flags |= ISDECLARED;
         } else {
                 char *name = sym->name;
                 Symbol **h;
 
                 sym = newsym(ns);
                 sym->name = xstrdup(name);
- h = &htab[hash(yytext)];
+ h = &htab[hash(name)];
                 sym->hash = *h;
                 *h = sym;
         }
diff --git a/cc1/types.c b/cc1/types.c
index 31424a3..f3b6577 100644
--- a/cc1/types.c
+++ b/cc1/types.c
_AT_@ -283,6 +283,7 @@ mktype(Type *tp, unsigned op, short nelem, Type *pars[])
 
         type.type = tp;
         type.op = op;
+ type.printed = 0;
         type.letter = letters[op];
         type.pars = pars;
         type.n.elem = nelem;
_AT_@ -351,7 +352,8 @@ eqtype(Type *tp1, Type *tp2)
                 return 1;
         case ENUM:
                 break;
- case INT: case FLOAT:
+ case INT:
+ case FLOAT:
                 return tp1->letter == tp2->letter;
         default:
                 fputs("internal type error, aborting\n", stderr);
diff --git a/inc/cc.h b/inc/cc.h
index 41a1dda..6519957 100644
--- a/inc/cc.h
+++ b/inc/cc.h
_AT_@ -65,6 +65,7 @@ typedef unsigned bool;
 #define L_REGISTER 'R'
 #define L_FIELD 'M'
 #define L_AUTO 'A'
+#define L_EXTERN 'X'
 
 extern void die(const char *fmt, ...);
 extern void *xmalloc(size_t size);
Received on Mon Aug 10 2015 - 17:36:47 CEST

This archive was generated by hypermail 2.3.0 : Mon Aug 10 2015 - 17:48:14 CEST