~mcf/cproc

54303c25f3d61ab8696e233bfe5d1d154617a600 — Michael Forney 2 years ago 2d036a0
Merge headers into cc.h
24 files changed, 415 insertions(+), 439 deletions(-)

D backend.h
R token.h => cc.h
M decl.c
D decl.h
M deps.mk
M eval.c
D eval.h
M expr.c
D expr.h
M init.c
D init.h
M main.c
M pp.c
D pp.h
M qbe.c
M scan.c
D scan.h
M scope.c
D scope.h
M stmt.c
D stmt.h
M token.c
M type.c
D type.h
D backend.h => backend.h +0 -41
@@ 1,41 0,0 @@
struct gotolabel {
	struct value *label;
	_Bool defined;
};

struct switchcases {
	void *root;
	struct value *defaultlabel;
};

struct repr;
struct decl;
struct expr;
struct init;
struct scope;
struct type;

struct switchcases *mkswitch(void);
void switchcase(struct switchcases *, uint64_t, struct value *);

struct value *mkblock(char *);
struct value *mkglobal(char *, _Bool);
struct value *mkintconst(struct repr *, uint64_t);

uint64_t intconstvalue(struct value *);

struct func *mkfunc(char *, struct type *, struct scope *);
struct type *functype(struct func *);
void funclabel(struct func *, struct value *);
struct value *funcexpr(struct func *, struct expr *);
void funcjmp(struct func *, struct value *);
void funcjnz(struct func *, struct value *, struct value *, struct value *);
void funcret(struct func *, struct value *);
struct gotolabel *funcgoto(struct func *, char *);
void funcswitch(struct func *, struct value *, struct switchcases *, struct value *);
void funcinit(struct func *, struct decl *, struct init *);

void emitfunc(struct func *, _Bool);
void emitdata(struct decl *,  struct init *);

extern struct repr i8, i16, i32, i64, f32, f64;

R token.h => cc.h +388 -0
@@ 1,3 1,5 @@
/* token */

enum tokenkind {
	TNONE,



@@ 122,3 124,389 @@ extern struct token tok;

void tokprint(const struct token *);
_Noreturn void error(const struct location *, const char *, ...);
struct token;

/* scan */

int scanfrom(const char *file);
void scan(struct token *);
struct location;

void ppinit(const char *);

void next(void);
_Bool peek(int);
char *expect(int, const char *);
_Bool consume(int);

/* type */

enum typequal {
	QUALNONE,

	QUALCONST    = 1<<1,
	QUALRESTRICT = 1<<2,
	QUALVOLATILE = 1<<3,
	QUALATOMIC   = 1<<4,
};

enum typekind {
	TYPENONE,

	TYPEQUALIFIED,
	TYPEVOID,
	TYPEBASIC,
	TYPEPOINTER,
	TYPEARRAY,
	TYPEFUNC,
	TYPESTRUCT,
	TYPEUNION,
};

enum typeprop {
	PROPNONE,

	PROPOBJECT  = 1<<0,
	PROPCHAR    = 1<<1,
	PROPINT     = 1<<2,
	PROPREAL    = 1<<3,
	PROPARITH   = 1<<4,
	PROPSCALAR  = 1<<5,
	PROPAGGR    = 1<<6,
	PROPDERIVED = 1<<7,
	PROPFLOAT   = 1<<8,
};

struct param {
	char *name;
	struct type *type;
	struct value *value;
	struct param *next;
};

struct bitfield {
	short before;  /* number of bits in the storage unit before the bit-field */
	short after;   /* number of bits in the storage unit after the bit-field */
};

struct member {
	char *name;
	struct type *type;
	uint64_t offset;
	struct bitfield bits;
	struct member *next;
};

struct type {
	enum typekind kind;
	int align;
	uint64_t size;
	struct repr *repr;
	union {
		struct type *base;
		struct list link;  /* used only during construction of type */
	};
	_Bool incomplete;
	union {
		struct {
			enum typequal kind;
		} qualified;
		struct {
			enum {
				BASICBOOL,
				BASICCHAR,
				BASICSHORT,
				BASICINT,
				BASICENUM,
				BASICLONG,
				BASICLONGLONG,
				BASICFLOAT,
				BASICDOUBLE,
				BASICLONGDOUBLE,
			} kind;
			_Bool issigned, iscomplex;
		} basic;
		struct {
			uint64_t length;
		} array;
		struct {
			_Bool isprototype, isvararg, isnoreturn, paraminfo;
			struct param *params;
		} func;
		struct {
			char *tag;
			struct member *members;
		} structunion;
	};
};

struct type *mktype(enum typekind);
struct type *mkqualifiedtype(struct type *, enum typequal);
struct type *mkpointertype(struct type *);
struct type *mkarraytype(struct type *, uint64_t);

_Bool typecompatible(struct type *, struct type *);
_Bool typesame(struct type *, struct type *);
struct type *typecomposite(struct type *, struct type *);
struct type *typeunqual(struct type *, enum typequal *);
struct type *typecommonreal(struct type *, struct type *);
struct type *typeargpromote(struct type *);
struct type *typeintpromote(struct type *);
enum typeprop typeprop(struct type *);
struct member *typemember(struct type *, const char *, uint64_t *);

struct param *mkparam(char *, struct type *);

extern struct type typevoid;
extern struct type typebool;
extern struct type typechar, typeschar, typeuchar;
extern struct type typeshort, typeushort;
extern struct type typeint, typeuint;
extern struct type typelong, typeulong;
extern struct type typellong, typeullong;
extern struct type typefloat, typedouble, typelongdouble;
extern struct type typevalist, typevalistptr;

/* decl */

enum declkind {
	DECLTYPE,
	DECLOBJECT,
	DECLFUNC,
	DECLCONST,
	DECLBUILTIN,
};

enum linkage {
	LINKNONE,
	LINKINTERN,
	LINKEXTERN,
};

enum builtinkind {
	BUILTINALLOCA,
	BUILTINCONSTANTP,
	BUILTININFF,
	BUILTINNANF,
	BUILTINOFFSETOF,
	BUILTINVAARG,
	BUILTINVACOPY,
	BUILTINVAEND,
	BUILTINVALIST,
	BUILTINVASTART,
};

struct decl {
	enum declkind kind;
	enum linkage linkage;
	struct type *type;
	struct value *value;

	/* objects and functions */
	struct list link;
	int align;  /* may be more strict than type requires */
	_Bool tentative, defined;

	/* built-ins */
	enum builtinkind builtin;
};

struct scope;
struct func;

struct decl *mkdecl(enum declkind, struct type *, enum linkage);
_Bool decl(struct scope *, struct func *);
struct type *typename(struct scope *);

struct expr;
struct decl *stringdecl(struct expr *);

void emittentativedefns(void);

/* scope */

struct scope {
	struct hashtable *tags;
	struct hashtable *decls;
	struct value *breaklabel;
	struct value *continuelabel;
	struct switchcases *switchcases;
	struct scope *parent;
};

void scopeinit(void);
struct scope *mkscope(struct scope *);
struct scope *delscope(struct scope *);

struct decl;
void scopeputdecl(struct scope *, const char *, struct decl *);
struct decl *scopegetdecl(struct scope *, const char *, _Bool);

struct type;
void scopeputtag(struct scope *, const char *, struct type *);
struct type *scopegettag(struct scope *, const char *, _Bool);

extern struct scope filescope;

/* expr */

enum exprkind {
	/* primary expression */
	EXPRIDENT,
	EXPRCONST,
	EXPRSTRING,

	/* postfix expression */
	EXPRCALL,
	/* member E.M gets transformed to *(typeof(E.M) *)((char *)E + offsetof(typeof(E), M)) */
	EXPRINCDEC,
	EXPRCOMPOUND,
	/* subscript E1[E2] gets transformed to *((E1)+(E2)) */

	EXPRUNARY,
	EXPRCAST,
	EXPRBINARY,
	EXPRCOND,
	EXPRASSIGN,
	EXPRCOMMA,

	EXPRBUILTIN,
	EXPRTEMP,
};

enum exprflags {
	EXPRFLAG_LVAL    = 1<<0,
	EXPRFLAG_DECAYED = 1<<1,
};

struct expr {
	enum exprkind kind;
	enum exprflags flags;
	struct type *type;
	struct expr *next;
	union {
		struct {
			struct decl *decl;
		} ident;
		union {
			uint64_t i;
			double f;
		} constant;
		struct {
			char *data;
			size_t size;
		} string;
		struct {
			struct expr *func, *args;
			size_t nargs;
		} call;
		struct {
			struct init *init;
		} compound;
		struct {
			int op;
			_Bool post;
			struct expr *base;
		} incdec;
		struct {
			int op;
			struct expr *base;
		} unary;
		struct {
			struct expr *e;
		} cast;
		struct {
			int op;
			struct expr *l, *r;
		} binary;
		struct {
			struct expr *e, *t, *f;
		} cond;
		struct {
			struct expr *l, *r;
		} assign;
		struct {
			struct expr *exprs;
		} comma;
		struct {
			int kind;
			struct expr *arg;
		} builtin;
		struct value *temp;
	};
};

struct scope;

struct expr *expr(struct scope *);
struct expr *assignexpr(struct scope *);
uint64_t intconstexpr(struct scope *, _Bool);
void delexpr(struct expr *);

struct expr *exprconvert(struct expr *, struct type *);

/* eval */

struct expr *eval(struct expr *);

/* init */

struct init {
	uint64_t start, end;
	struct expr *expr;
	struct init *next;
};

struct scope;
struct type;

struct init *mkinit(uint64_t, uint64_t, struct expr *);
struct init *parseinit(struct scope *, struct type *);
struct func;
struct scope;

void stmt(struct func *, struct scope *);

/* backend */

struct gotolabel {
	struct value *label;
	_Bool defined;
};

struct switchcases {
	void *root;
	struct value *defaultlabel;
};

struct repr;
struct decl;
struct expr;
struct init;
struct scope;
struct type;

struct switchcases *mkswitch(void);
void switchcase(struct switchcases *, uint64_t, struct value *);

struct value *mkblock(char *);
struct value *mkglobal(char *, _Bool);
struct value *mkintconst(struct repr *, uint64_t);

uint64_t intconstvalue(struct value *);

struct func *mkfunc(char *, struct type *, struct scope *);
struct type *functype(struct func *);
void funclabel(struct func *, struct value *);
struct value *funcexpr(struct func *, struct expr *);
void funcjmp(struct func *, struct value *);
void funcjnz(struct func *, struct value *, struct value *, struct value *);
void funcret(struct func *, struct value *);
struct gotolabel *funcgoto(struct func *, char *);
void funcswitch(struct func *, struct value *, struct switchcases *, struct value *);
void funcinit(struct func *, struct decl *, struct init *);

void emitfunc(struct func *, _Bool);
void emitdata(struct decl *,  struct init *);

extern struct repr i8, i16, i32, i64, f32, f64;

M decl.c => decl.c +1 -9
@@ 7,16 7,8 @@
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "backend.h"
#include "decl.h"
#include "expr.h"
#include "cc.h"
#include "htab.h"
#include "init.h"
#include "pp.h"
#include "scope.h"
#include "stmt.h"
#include "token.h"
#include "type.h"

static struct list tentativedefns = {&tentativedefns, &tentativedefns};


D decl.h => decl.h +0 -53
@@ 1,53 0,0 @@
enum declkind {
	DECLTYPE,
	DECLOBJECT,
	DECLFUNC,
	DECLCONST,
	DECLBUILTIN,
};

enum linkage {
	LINKNONE,
	LINKINTERN,
	LINKEXTERN,
};

enum builtinkind {
	BUILTINALLOCA,
	BUILTINCONSTANTP,
	BUILTININFF,
	BUILTINNANF,
	BUILTINOFFSETOF,
	BUILTINVAARG,
	BUILTINVACOPY,
	BUILTINVAEND,
	BUILTINVALIST,
	BUILTINVASTART,
};

struct decl {
	enum declkind kind;
	enum linkage linkage;
	struct type *type;
	struct value *value;

	/* objects and functions */
	struct list link;
	int align;  /* may be more strict than type requires */
	_Bool tentative, defined;

	/* built-ins */
	enum builtinkind builtin;
};

struct scope;
struct func;

struct decl *mkdecl(enum declkind, struct type *, enum linkage);
_Bool decl(struct scope *, struct func *);
struct type *typename(struct scope *);

struct expr;
struct decl *stringdecl(struct expr *);

void emittentativedefns(void);

M deps.mk => deps.mk +12 -16
@@ 1,22 1,18 @@
driver.o: driver.c util.h config.h
util.o: util.c util.h
decl.o: decl.c util.h backend.h decl.h expr.h htab.h init.h pp.h scope.h \
 stmt.h token.h type.h
eval.o: eval.c util.h backend.h decl.h eval.h expr.h token.h type.h
expr.o: expr.c util.h decl.h eval.h expr.h init.h pp.h scope.h token.h \
 type.h
decl.o: decl.c util.h cc.h htab.h
eval.o: eval.c util.h cc.h
expr.o: expr.c util.h cc.h
htab.o: htab.c util.h htab.h
init.o: init.c util.h decl.h expr.h init.h pp.h token.h type.h
main.o: main.c util.h arg.h decl.h pp.h scope.h token.h
pp.o: pp.c util.h pp.h scan.h token.h
scan.o: scan.c util.h scan.h token.h
scope.o: scope.c util.h decl.h htab.h scope.h type.h
init.o: init.c util.h cc.h
main.o: main.c util.h arg.h cc.h
pp.o: pp.c util.h cc.h
scan.o: scan.c util.h cc.h
scope.o: scope.c util.h cc.h htab.h
siphash.o: siphash.c
stmt.o: stmt.c util.h backend.h decl.h expr.h pp.h scope.h stmt.h token.h \
 type.h
stmt.o: stmt.c util.h cc.h
tree.o: tree.c util.h tree.h
token.o: token.c util.h token.h
type.o: type.c util.h backend.h type.h
token.o: token.c util.h cc.h
type.o: type.c util.h cc.h
util.o: util.c util.h
qbe.o: qbe.c util.h backend.h decl.h eval.h expr.h htab.h init.h scope.h \
 token.h tree.h type.h ops.h
qbe.o: qbe.c util.h cc.h htab.h tree.h ops.h

M eval.c => eval.c +1 -6
@@ 2,12 2,7 @@
#include <stddef.h>
#include <stdint.h>
#include "util.h"
#include "backend.h"
#include "decl.h"
#include "eval.h"
#include "expr.h"
#include "token.h"
#include "type.h"
#include "cc.h"

static void
binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r)

D eval.h => eval.h +0 -1
@@ 1,1 0,0 @@
struct expr *eval(struct expr *);

M expr.c => expr.c +1 -8
@@ 8,14 8,7 @@
#include <string.h>
#include <strings.h>
#include "util.h"
#include "decl.h"
#include "eval.h"
#include "expr.h"
#include "init.h"
#include "pp.h"
#include "scope.h"
#include "token.h"
#include "type.h"
#include "cc.h"

static struct expr *
mkexpr(enum exprkind k, struct type *t, enum exprflags flags)

D expr.h => expr.h +0 -94
@@ 1,94 0,0 @@
enum exprkind {
	/* primary expression */
	EXPRIDENT,
	EXPRCONST,
	EXPRSTRING,

	/* postfix expression */
	EXPRCALL,
	/* member E.M gets transformed to *(typeof(E.M) *)((char *)E + offsetof(typeof(E), M)) */
	EXPRINCDEC,
	EXPRCOMPOUND,
	/* subscript E1[E2] gets transformed to *((E1)+(E2)) */

	EXPRUNARY,
	EXPRCAST,
	EXPRBINARY,
	EXPRCOND,
	EXPRASSIGN,
	EXPRCOMMA,

	EXPRBUILTIN,
	EXPRTEMP,
};

enum exprflags {
	EXPRFLAG_LVAL    = 1<<0,
	EXPRFLAG_DECAYED = 1<<1,
};

struct expr {
	enum exprkind kind;
	enum exprflags flags;
	struct type *type;
	struct expr *next;
	union {
		struct {
			struct decl *decl;
		} ident;
		union {
			uint64_t i;
			double f;
		} constant;
		struct {
			char *data;
			size_t size;
		} string;
		struct {
			struct expr *func, *args;
			size_t nargs;
		} call;
		struct {
			struct init *init;
		} compound;
		struct {
			int op;
			_Bool post;
			struct expr *base;
		} incdec;
		struct {
			int op;
			struct expr *base;
		} unary;
		struct {
			struct expr *e;
		} cast;
		struct {
			int op;
			struct expr *l, *r;
		} binary;
		struct {
			struct expr *e, *t, *f;
		} cond;
		struct {
			struct expr *l, *r;
		} assign;
		struct {
			struct expr *exprs;
		} comma;
		struct {
			int kind;
			struct expr *arg;
		} builtin;
		struct value *temp;
	};
};

struct scope;

struct expr *expr(struct scope *);
struct expr *assignexpr(struct scope *);
uint64_t intconstexpr(struct scope *, _Bool);
void delexpr(struct expr *);

struct expr *exprconvert(struct expr *, struct type *);

M init.c => init.c +1 -6
@@ 6,12 6,7 @@
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "decl.h"
#include "expr.h"
#include "init.h"
#include "pp.h"
#include "token.h"
#include "type.h"
#include "cc.h"

struct object {
	uint64_t offset;

D init.h => init.h +0 -11
@@ 1,11 0,0 @@
struct init {
	uint64_t start, end;
	struct expr *expr;
	struct init *next;
};

struct scope;
struct type;

struct init *mkinit(uint64_t, uint64_t, struct expr *);
struct init *parseinit(struct scope *, struct type *);

M main.c => main.c +1 -4
@@ 5,10 5,7 @@
#include <stdnoreturn.h>
#include "util.h"
#include "arg.h"
#include "decl.h"
#include "pp.h"
#include "scope.h"
#include "token.h"
#include "cc.h"

static noreturn void
usage(void)

M pp.c => pp.c +2 -3
@@ 1,12 1,11 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "pp.h"
#include "scan.h"
#include "token.h"
#include "cc.h"

static struct token pending;


D pp.h => pp.h +0 -8
@@ 1,8 0,0 @@
struct location;

void ppinit(const char *);

void next(void);
_Bool peek(int);
char *expect(int, const char *);
_Bool consume(int);

M qbe.c => qbe.c +1 -8
@@ 6,16 6,9 @@
#include <string.h>
#include <inttypes.h>
#include "util.h"
#include "backend.h"
#include "decl.h"
#include "eval.h"
#include "expr.h"
#include "cc.h"
#include "htab.h"
#include "init.h"
#include "scope.h"
#include "token.h"
#include "tree.h"
#include "type.h"

struct name {
	char *str;

M scan.c => scan.c +2 -2
@@ 1,12 1,12 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "scan.h"
#include "token.h"
#include "cc.h"

struct buffer {
	char *str;

D scan.h => scan.h +0 -4
@@ 1,4 0,0 @@
struct token;

int scanfrom(const char *file);
void scan(struct token *);

M scope.c => scope.c +1 -3
@@ 3,10 3,8 @@
#include <stdint.h>
#include <string.h>
#include "util.h"
#include "decl.h"
#include "cc.h"
#include "htab.h"
#include "scope.h"
#include "type.h"

struct scope filescope;


D scope.h => scope.h +0 -22
@@ 1,22 0,0 @@
struct scope {
	struct hashtable *tags;
	struct hashtable *decls;
	struct value *breaklabel;
	struct value *continuelabel;
	struct switchcases *switchcases;
	struct scope *parent;
};

void scopeinit(void);
struct scope *mkscope(struct scope *);
struct scope *delscope(struct scope *);

struct decl;
void scopeputdecl(struct scope *, const char *, struct decl *);
struct decl *scopegetdecl(struct scope *, const char *, _Bool);

struct type;
void scopeputtag(struct scope *, const char *, struct type *);
struct type *scopegettag(struct scope *, const char *, _Bool);

extern struct scope filescope;

M stmt.c => stmt.c +1 -8
@@ 5,14 5,7 @@
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "backend.h"
#include "decl.h"
#include "expr.h"
#include "pp.h"
#include "scope.h"
#include "stmt.h"
#include "token.h"
#include "type.h"
#include "cc.h"

static bool
gotolabel(struct func *f)

D stmt.h => stmt.h +0 -4
@@ 1,4 0,0 @@
struct func;
struct scope;

void stmt(struct func *, struct scope *);

M token.c => token.c +2 -1
@@ 1,8 1,9 @@
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "util.h"
#include "token.h"
#include "cc.h"

struct token tok;


M type.c => type.c +1 -2
@@ 4,8 4,7 @@
#include <stdint.h>
#include <string.h>
#include "util.h"
#include "backend.h"
#include "type.h"
#include "cc.h"

struct type typevoid       = {.kind = TYPEVOID, .incomplete = true};


D type.h => type.h +0 -125
@@ 1,125 0,0 @@
enum typequal {
	QUALNONE,

	QUALCONST    = 1<<1,
	QUALRESTRICT = 1<<2,
	QUALVOLATILE = 1<<3,
	QUALATOMIC   = 1<<4,
};

enum typekind {
	TYPENONE,

	TYPEQUALIFIED,
	TYPEVOID,
	TYPEBASIC,
	TYPEPOINTER,
	TYPEARRAY,
	TYPEFUNC,
	TYPESTRUCT,
	TYPEUNION,
};

enum typeprop {
	PROPNONE,

	PROPOBJECT  = 1<<0,
	PROPCHAR    = 1<<1,
	PROPINT     = 1<<2,
	PROPREAL    = 1<<3,
	PROPARITH   = 1<<4,
	PROPSCALAR  = 1<<5,
	PROPAGGR    = 1<<6,
	PROPDERIVED = 1<<7,
	PROPFLOAT   = 1<<8,
};

struct param {
	char *name;
	struct type *type;
	struct value *value;
	struct param *next;
};

struct bitfield {
	short before;  /* number of bits in the storage unit before the bit-field */
	short after;   /* number of bits in the storage unit after the bit-field */
};

struct member {
	char *name;
	struct type *type;
	uint64_t offset;
	struct bitfield bits;
	struct member *next;
};

struct type {
	enum typekind kind;
	int align;
	uint64_t size;
	struct repr *repr;
	union {
		struct type *base;
		struct list link;  /* used only during construction of type */
	};
	_Bool incomplete;
	union {
		struct {
			enum typequal kind;
		} qualified;
		struct {
			enum {
				BASICBOOL,
				BASICCHAR,
				BASICSHORT,
				BASICINT,
				BASICENUM,
				BASICLONG,
				BASICLONGLONG,
				BASICFLOAT,
				BASICDOUBLE,
				BASICLONGDOUBLE,
			} kind;
			_Bool issigned, iscomplex;
		} basic;
		struct {
			uint64_t length;
		} array;
		struct {
			_Bool isprototype, isvararg, isnoreturn, paraminfo;
			struct param *params;
		} func;
		struct {
			char *tag;
			struct member *members;
		} structunion;
	};
};

struct type *mktype(enum typekind);
struct type *mkqualifiedtype(struct type *, enum typequal);
struct type *mkpointertype(struct type *);
struct type *mkarraytype(struct type *, uint64_t);

_Bool typecompatible(struct type *, struct type *);
_Bool typesame(struct type *, struct type *);
struct type *typecomposite(struct type *, struct type *);
struct type *typeunqual(struct type *, enum typequal *);
struct type *typecommonreal(struct type *, struct type *);
struct type *typeargpromote(struct type *);
struct type *typeintpromote(struct type *);
enum typeprop typeprop(struct type *);
struct member *typemember(struct type *, const char *, uint64_t *);

struct param *mkparam(char *, struct type *);

extern struct type typevoid;
extern struct type typebool;
extern struct type typechar, typeschar, typeuchar;
extern struct type typeshort, typeushort;
extern struct type typeint, typeuint;
extern struct type typelong, typeulong;
extern struct type typellong, typeullong;
extern struct type typefloat, typedouble, typelongdouble;
extern struct type typevalist, typevalistptr;