shithub: femtolisp

Download patch

ref: f02ba63fa7b86631ccd8d71157dd88e745e7f1cc
parent: 721152be3a42fbebed2fc4bb947253ad558b4f91
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Nov 10 13:55:21 EST 2024

add FL(x) accessor and disable TLS for now

TLS will be disabled until (if) it's actually needed for anything
specific.

--- a/builtins.c
+++ b/builtins.c
@@ -23,9 +23,9 @@
 BUILTIN("nconc", nconc)
 {
 	if(nargs == 0)
-		return fl->FL_NIL;
+		return FL(FL_NIL);
 
-	value_t lst, first = fl->FL_NIL;
+	value_t lst, first = FL(FL_NIL);
 	value_t *pcdr = &first;
 	cons_t *c;
 	int i = 0;
@@ -40,7 +40,7 @@
 			while(iscons(c->cdr))
 				c = (cons_t*)ptr(c->cdr);
 			pcdr = &c->cdr;
-		}else if(lst != fl->FL_NIL)
+		}else if(lst != FL(FL_NIL))
 			type_error("cons", lst);
 	}
 	*pcdr = lst;
@@ -61,7 +61,7 @@
 			return bind;
 		v = cdr_(v);
 	}
-	return fl->FL_F;
+	return FL(FL_F);
 }
 
 BUILTIN("memq", memq)
@@ -74,7 +74,7 @@
 		if((c = ptr(v))->car == args[0])
 			return v;
 	}
-	return fl->FL_F;
+	return FL(FL_F);
 }
 
 BUILTIN("length", length)
@@ -86,7 +86,7 @@
 
 	if(isvector(a))
 		return fixnum(vector_size(a));
-	if(a == fl->FL_NIL)
+	if(a == FL(FL_NIL))
 		return fixnum(0);
 	if(iscons(a)){
 		size_t n = 0;
@@ -105,9 +105,9 @@
 	}
 	if(iscprim(a)){
 		cv = (cvalue_t*)ptr(a);
-		if(cp_class(cv) == fl->bytetype)
+		if(cp_class(cv) == FL(bytetype))
 			return fixnum(1);
-		if(cp_class(cv) == fl->runetype)
+		if(cp_class(cv) == FL(runetype))
 			return fixnum(runelen(*(Rune*)cp_data(cv)));
 	}
 	if(iscvalue(a) && cv_class(ptr(a))->eltype != nil)
@@ -140,7 +140,7 @@
 {
 	argcount(nargs, 1);
 	return (issymbol(args[0]) &&
-			iskeyword((symbol_t*)ptr(args[0]))) ? fl->FL_T : fl->FL_F;
+			iskeyword((symbol_t*)ptr(args[0]))) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("top-level-value", top_level_value)
@@ -176,9 +176,9 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	value_t lst = fl->FL_NIL;
+	value_t lst = FL(FL_NIL);
 	fl_gc_handle(&lst);
-	global_env_list(fl->symtab, &lst);
+	global_env_list(FL(symtab), &lst);
 	fl_free_gc_handles(1);
 	return lst;
 }
@@ -187,13 +187,13 @@
 {
 	argcount(nargs, 1);
 	if(issymbol(args[0]))
-		return isconstant((symbol_t*)ptr(args[0])) ? fl->FL_T : fl->FL_F;
+		return isconstant((symbol_t*)ptr(args[0])) ? FL(FL_T) : FL(FL_F);
 	if(iscons(args[0])){
-		if(car_(args[0]) == fl->QUOTE)
-			return fl->FL_T;
-		return fl->FL_F;
+		if(car_(args[0]) == FL(QUOTE))
+			return FL(FL_T);
+		return FL(FL_F);
 	}
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 BUILTIN("integer-valued?", integer_valuedp)
@@ -201,11 +201,11 @@
 	argcount(nargs, 1);
 	value_t v = args[0];
 	if(isfixnum(v))
-		return fl->FL_T;
+		return FL(FL_T);
 	if(iscprim(v)){
 		numerictype_t nt = cp_numtype((cprim_t*)ptr(v));
 		if(nt < T_FLOAT)
-			return fl->FL_T;
+			return FL(FL_T);
 		void *data = cp_data((cprim_t*)ptr(v));
 		if(nt == T_FLOAT){
 			float f = *(float*)data;
@@ -212,7 +212,7 @@
 			if(f < 0)
 				f = -f;
 			if(f <= FLT_MAXINT && (float)(int32_t)f == f)
-				return fl->FL_T;
+				return FL(FL_T);
 		}else{
 			assert(nt == T_DOUBLE);
 			double d = *(double*)data;
@@ -219,10 +219,10 @@
 			if(d < 0)
 				d = -d;
 			if(d <= DBL_MAXINT && (double)(int64_t)d == d)
-				return fl->FL_T;
+				return FL(FL_T);
 		}
 	}
-	return fl->FL_F;
+	return FL(FL_F);
 }
 
 BUILTIN("integer?", integerp)
@@ -231,7 +231,7 @@
 	value_t v = args[0];
 	return (isfixnum(v) ||
 			(iscprim(v) && cp_numtype((cprim_t*)ptr(v)) < T_FLOAT)) ?
-		fl->FL_T : fl->FL_F;
+		FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("bignum?", bignump)
@@ -239,7 +239,7 @@
 	argcount(nargs, 1);
 	value_t v = args[0];
 	return (iscvalue(v) && cp_numtype((cprim_t*)ptr(v)) == T_MPINT) ?
-		fl->FL_T : fl->FL_F;
+		FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("fixnum", fixnum)
@@ -291,11 +291,11 @@
 		argcount(nargs, 1);
 	i = toulong(args[0]);
 	if(i < 0)
-		lerrorf(fl->ArgError, "invalid size: %d", i);
+		lerrorf(FL(ArgError), "invalid size: %d", i);
 	v = alloc_vector((unsigned)i, 0);
 	a = 1;
 	for(k = 0; k < i; k++){
-		f = a < nargs ? args[a] : fl->FL_UNSPECIFIED;
+		f = a < nargs ? args[a] : FL(FL_UNSPECIFIED);
 		vector_elt(v, k) = f;
 		if((a = (a + 1) % nargs) < 1)
 			a = 1;
@@ -354,8 +354,8 @@
 	}
 	char *ptr = tostring(args[0]);
 	if(chdir(ptr))
-		lerrorf(fl->IOError, "could not cd to %s", ptr);
-	return fl->FL_T;
+		lerrorf(FL(IOError), "could not cd to %s", ptr);
+	return FL(FL_T);
 }
 
 BUILTIN("path-exists?", path_existsp)
@@ -362,7 +362,7 @@
 {
 	argcount(nargs, 1);
 	char *path = tostring(args[0]);
-	return access(path, F_OK) == 0 ? fl->FL_T : fl->FL_F;
+	return access(path, F_OK) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("os-getenv", os_getenv)
@@ -371,9 +371,9 @@
 	char *name = tostring(args[0]);
 	char *val = getenv(name);
 	if(val == nil)
-		return fl->FL_F;
+		return FL(FL_F);
 	if(*val == 0)
-		return symbol_value(fl->emptystringsym);
+		return symbol_value(FL(emptystringsym));
 	return cvalue_static_cstring(val);
 }
 
@@ -382,7 +382,7 @@
 	argcount(nargs, 2);
 	char *name = tostring(args[0]);
 	int result;
-	if(args[1] == fl->FL_F)
+	if(args[1] == FL(FL_F))
 		result = unsetenv(name);
 	else{
 		char *val = tostring(args[1]);
@@ -389,8 +389,8 @@
 		result = setenv(name, val, 1);
 	}
 	if(result != 0)
-		lerrorf(fl->ArgError, "invalid environment variable");
-	return fl->FL_T;
+		lerrorf(FL(ArgError), "invalid environment variable");
+	return FL(FL_T);
 }
 
 BUILTIN("rand", rand)
--- a/cvalues.c
+++ b/cvalues.c
@@ -14,15 +14,15 @@
 void
 add_finalizer(cvalue_t *cv)
 {
-	if(fl->nfinalizers == fl->maxfinalizers){
-		size_t nn = fl->maxfinalizers == 0 ? 256 : fl->maxfinalizers*2;
-		cvalue_t **temp = LLT_REALLOC(fl->Finalizers, nn*sizeof(cvalue_t*));
+	if(FL(nfinalizers) == FL(maxfinalizers)){
+		size_t nn = FL(maxfinalizers) == 0 ? 256 : FL(maxfinalizers)*2;
+		cvalue_t **temp = LLT_REALLOC(FL(Finalizers), nn*sizeof(cvalue_t*));
 		if(temp == nil)
-			lerrorf(fl->MemoryError, "out of memory");
-		fl->Finalizers = temp;
-		fl->maxfinalizers = nn;
+			lerrorf(FL(MemoryError), "out of memory");
+		FL(Finalizers) = temp;
+		FL(maxfinalizers) = nn;
 	}
-	fl->Finalizers[fl->nfinalizers++] = cv;
+	FL(Finalizers)[FL(nfinalizers)++] = cv;
 }
 
 // remove dead objects from finalization list in-place
@@ -29,8 +29,8 @@
 void
 sweep_finalizers(void)
 {
-	cvalue_t **lst = fl->Finalizers;
-	size_t n = 0, ndel = 0, l = fl->nfinalizers;
+	cvalue_t **lst = FL(Finalizers);
+	size_t n = 0, ndel = 0, l = FL(nfinalizers);
 	cvalue_t *tmp;
 #define SWAP_sf(a, b) (tmp = a, a = b, b = tmp, 1)
 	if(l == 0)
@@ -45,7 +45,7 @@
 			fltype_t *t = cv_class(tmp);
 			if(t->vtable != nil && t->vtable->finalize != nil)
 				t->vtable->finalize(tagptr(tmp, TAG_CVALUE));
-			if(!isinlined(tmp) && owned(tmp) && !fl->exiting){
+			if(!isinlined(tmp) && owned(tmp) && !FL(exiting)){
 				memset(cv_data(tmp), 0xbb, cv_len(tmp));
 				LLT_FREE(cv_data(tmp));
 			}
@@ -53,13 +53,13 @@
 		}
 	}while((n < l-ndel) && SWAP_sf(lst[n], lst[n+ndel]));
 
-	fl->nfinalizers -= ndel;
+	FL(nfinalizers) -= ndel;
 #ifdef VERBOSEGC
 	if(ndel > 0)
 		printf("GC: finalized %d objects\n", ndel);
 #endif
 
-	fl->malloc_pressure = 0;
+	FL(malloc_pressure) = 0;
 }
 
 // compute the size of the metadata object for a cvalue
@@ -107,9 +107,9 @@
 	if(valid_numtype(type->numtype) && type->numtype != T_MPINT)
 		return cprim(type, sz);
 
-	if(type->eltype == fl->bytetype){
+	if(type->eltype == FL(bytetype)){
 		if(sz == 0)
-			return symbol_value(fl->emptystringsym);
+			return symbol_value(FL(emptystringsym));
 		sz++;
 		str = 1;
 	}
@@ -121,13 +121,13 @@
 		if(!nofinalize && type->vtable != nil && type->vtable->finalize != nil)
 			add_finalizer(pcv);
 	}else{
-		if(fl->malloc_pressure > ALLOC_LIMIT_TRIGGER)
+		if(FL(malloc_pressure) > ALLOC_LIMIT_TRIGGER)
 			gc(0);
 		pcv = alloc_words(CVALUE_NWORDS);
 		pcv->type = type;
 		pcv->data = LLT_ALLOC(sz);
 		autorelease(pcv);
-		fl->malloc_pressure += sz;
+		FL(malloc_pressure) += sz;
 	}
 	if(str)
 		((char*)pcv->data)[--sz] = '\0';
@@ -162,7 +162,7 @@
 	pcv->data = ptr;
 	pcv->len = sz;
 	pcv->type = type;
-	if(parent != fl->NIL){
+	if(parent != FL(NIL)){
 		pcv->type = (fltype_t*)(((uintptr_t)pcv->type) | CV_PARENT_BIT);
 		pcv->parent = parent;
 	}
@@ -173,13 +173,13 @@
 value_t
 cvalue_string(size_t sz)
 {
-	return cvalue(fl->stringtype, sz);
+	return cvalue(FL(stringtype), sz);
 }
 
 value_t
 cvalue_static_cstring(const char *str)
 {
-	return cvalue_from_ref(fl->stringtype, (char*)str, strlen(str), fl->NIL);
+	return cvalue_from_ref(FL(stringtype), (char*)str, strlen(str), FL(NIL));
 }
 
 value_t
@@ -252,10 +252,10 @@
 	{ \
 		if(nargs == 0){ \
 			PUSH(fixnum(0)); \
-			args = &fl->Stack[fl->SP-1]; \
+			args = &FL(Stack)[FL(SP)-1]; \
 		} \
-		value_t cp = cprim(fl->typenam##type, sizeof(ctype)); \
-		if(cvalue_##ctype##_init(fl->typenam##type, args[0], cp_data((cprim_t*)ptr(cp)))) \
+		value_t cp = cprim(FL(typenam##type), sizeof(ctype)); \
+		if(cvalue_##ctype##_init(FL(typenam##type), args[0], cp_data((cprim_t*)ptr(cp)))) \
 			type_error("number", args[0]); \
 		return cp; \
 	}
@@ -263,7 +263,7 @@
 #define num_ctor_ctor(typenam, ctype, tag) \
 	value_t mk_##typenam(ctype n) \
 	{ \
-		value_t cp = cprim(fl->typenam##type, sizeof(ctype)); \
+		value_t cp = cprim(FL(typenam##type), sizeof(ctype)); \
 		*(ctype*)cp_data((cprim_t*)ptr(cp)) = n; \
 		return cp; \
 	}
@@ -314,10 +314,10 @@
 {
 	if(nargs == 0){
 		PUSH(fixnum(0));
-		args = &fl->Stack[fl->SP-1];
+		args = &FL(Stack)[FL(SP)-1];
 	}
-	value_t cv = cvalue(fl->mpinttype, sizeof(mpint*));
-	if(cvalue_mpint_init(fl->mpinttype, args[0], cv_data((cvalue_t*)ptr(cv))))
+	value_t cv = cvalue(FL(mpinttype), sizeof(mpint*));
+	if(cvalue_mpint_init(FL(mpinttype), args[0], cv_data((cvalue_t*)ptr(cv))))
 		type_error("number", args[0]);
 	return cv;
 }
@@ -326,7 +326,7 @@
 value_t
 mk_mpint(mpint *n)
 {
-	value_t cv = cvalue(fl->mpinttype, sizeof(mpint*));
+	value_t cv = cvalue(FL(mpinttype), sizeof(mpint*));
 	*(mpint**)cvalue_data(cv) = n;
 	return cv;
 }
@@ -391,7 +391,7 @@
 				return 0;
 			}
 		}
-		lerrorf(fl->ArgError, "invalid enum value");
+		lerrorf(FL(ArgError), "invalid enum value");
 	}
 	if(isfixnum(arg))
 		n = (int)numval(arg);
@@ -401,7 +401,7 @@
 	}else
 		type_error("number", arg);
 	if((unsigned)n >= vector_size(syms))
-		lerrorf(fl->ArgError, "value out of range");
+		lerrorf(FL(ArgError), "value out of range");
 	*(int*)dest = n;
 	return 0;
 }
@@ -409,7 +409,7 @@
 BUILTIN("enum", enum)
 {
 	argcount(nargs, 2);
-	value_t type = fl_list2(fl->enumsym, args[0]);
+	value_t type = fl_list2(FL(enumsym), args[0]);
 	fltype_t *ft = get_type(type);
 	value_t cv = cvalue(ft, sizeof(int32_t));
 	cvalue_enum_init(ft, args[1], cp_data((cprim_t*)ptr(cv)));
@@ -429,7 +429,7 @@
 		return vector_size(arg);
 	if(iscons(arg))
 		return llength(arg);
-	if(arg == fl->NIL)
+	if(arg == FL(NIL))
 		return 0;
 	if(isarray(arg))
 		return cvalue_arraylen(arg);
@@ -449,7 +449,7 @@
 	if(iscons(cdr_(cdr_(type)))){
 		size_t tc = toulong(car_(cdr_(cdr_(type))));
 		if(tc != cnt)
-			lerrorf(fl->ArgError, "size mismatch");
+			lerrorf(FL(ArgError), "size mismatch");
 	}
 
 	sz = elsize * cnt;
@@ -462,7 +462,7 @@
 		}
 		return 0;
 	}
-	if(iscons(arg) || arg == fl->NIL){
+	if(iscons(arg) || arg == FL(NIL)){
 		i = 0;
 		while(iscons(arg)){
 			if(i == cnt){
@@ -475,7 +475,7 @@
 			arg = cdr_(arg);
 		}
 		if(i != cnt)
-			lerrorf(fl->ArgError, "size mismatch");
+			lerrorf(FL(ArgError), "size mismatch");
 		return 0;
 	}
 	if(iscvalue(arg)){
@@ -486,11 +486,11 @@
 				if(cv_len(cv) == sz)
 					memmove(dest, cv_data(cv), sz);
 				else
-					lerrorf(fl->ArgError, "size mismatch");
+					lerrorf(FL(ArgError), "size mismatch");
 				return 0;
 			}else{
 				// TODO: initialize array from different type elements
-				lerrorf(fl->ArgError, "element type mismatch");
+				lerrorf(FL(ArgError), "element type mismatch");
 			}
 		}
 	}
@@ -531,7 +531,7 @@
 		argcount(nargs, 3);
 	cnt = toulong(args[1]);
 	if(cnt < 0)
-		lerrorf(fl->ArgError, "invalid size: %d", cnt);
+		lerrorf(FL(ArgError), "invalid size: %d", cnt);
 
 	fltype_t *type = get_array_type(args[0]);
 	elsize = type->elsz;
@@ -613,29 +613,29 @@
 
 	if(iscons(type)){
 		value_t hed = car_(type);
-		if(hed == fl->structsym)
-			return cvalue_struct_offs(type, fl->NIL, 1, palign);
-		if(hed == fl->unionsym)
+		if(hed == FL(structsym))
+			return cvalue_struct_offs(type, FL(NIL), 1, palign);
+		if(hed == FL(unionsym))
 			return cvalue_union_size(type, palign);
-		if(hed == fl->pointersym || hed == fl->cfunctionsym){
+		if(hed == FL(pointersym) || hed == FL(cfunctionsym)){
 			*palign = offsetof(struct{ char a; void *i; }, i);
 			return sizeof(void*);
 		}
-		if(hed == fl->arraysym){
+		if(hed == FL(arraysym)){
 			value_t t = car(cdr_(type));
 			if(!iscons(cdr_(cdr_(type))))
-				lerrorf(fl->ArgError, "incomplete type");
+				lerrorf(FL(ArgError), "incomplete type");
 			value_t n = car_(cdr_(cdr_(type)));
 			size_t sz = toulong(n);
 			return sz * ctype_sizeof(t, palign);
 		}
-		if(hed == fl->enumsym){
+		if(hed == FL(enumsym)){
 			*palign = offsetof(struct{ char c; numerictype_t e; }, e);
 			return sizeof(numerictype_t);
 		}
 	}
 
-	lerrorf(fl->ArgError, "invalid c type");
+	lerrorf(FL(ArgError), "invalid c type");
 }
 
 // get pointer and size for any plain-old-data value
@@ -645,7 +645,7 @@
 	if(iscvalue(v)){
 		cvalue_t *pcv = ptr(v);
 		ios_t *x = value2c(ios_t*, v);
-		if(cv_class(pcv) == fl->iostreamtype && x->bm == bm_mem){
+		if(cv_class(pcv) == FL(iostreamtype) && x->bm == bm_mem){
 			*pdata = x->buf;
 			*psz = x->size;
 			return;
@@ -681,20 +681,20 @@
 {
 	argcount(nargs, 1);
 	switch(tag(args[0])){
-	case TAG_CONS: return fl->pairsym;
-	case TAG_NUM1: case TAG_NUM: return fl->fixnumsym;
-	case TAG_SYM: return fl->symbolsym;
-	case TAG_VECTOR: return fl->vectorsym;
+	case TAG_CONS: return FL(pairsym);
+	case TAG_NUM1: case TAG_NUM: return FL(fixnumsym);
+	case TAG_SYM: return FL(symbolsym);
+	case TAG_VECTOR: return FL(vectorsym);
 	case TAG_FUNCTION:
-		if(args[0] == fl->FL_T || args[0] == fl->FL_F)
-			return fl->booleansym;
-		if(args[0] == fl->NIL)
-			return fl->nullsym;
-		if(args[0] == fl->FL_EOF)
+		if(args[0] == FL(FL_T) || args[0] == FL(FL_F))
+			return FL(booleansym);
+		if(args[0] == FL(NIL))
+			return FL(nullsym);
+		if(args[0] == FL(FL_EOF))
 			return symbol("eof-object");
 		if(isbuiltin(args[0]))
-			return fl->builtinsym;
-		return fl->FUNCTION;
+			return FL(builtinsym);
+		return FL(FUNCTION);
 	}
 	return cv_type(ptr(args[0]));
 }
@@ -717,7 +717,7 @@
 	if(t->vtable != nil && t->vtable->relocate != nil)
 		t->vtable->relocate(v, ncv);
 	forward(v, ncv);
-	if(fl->exiting)
+	if(FL(exiting))
 		cv_autorelease(ptr(ncv));
 	return ncv;
 }
@@ -742,7 +742,7 @@
 		autorelease(ncv);
 		if(hasparent(cv)){
 			ncv->type = (fltype_t*)(((uintptr_t)ncv->type) & ~CV_PARENT_BIT);
-			ncv->parent = fl->NIL;
+			ncv->parent = FL(NIL);
 		}
 	}else{
 		ncv->data = &ncv->_space[0];
@@ -755,11 +755,11 @@
 {
 	argcount(nargs, 1);
 	if(iscons(args[0]) || isvector(args[0]))
-		lerrorf(fl->ArgError, "argument must be a leaf atom");
+		lerrorf(FL(ArgError), "argument must be a leaf atom");
 	if(!iscvalue(args[0]))
 		return args[0];
 	if(!cv_isPOD(ptr(args[0])))
-		lerrorf(fl->ArgError, "argument must be a plain-old-data type");
+		lerrorf(FL(ArgError), "argument must be a plain-old-data type");
 	return cvalue_copy(args[0]);
 }
 
@@ -768,7 +768,7 @@
 	argcount(nargs, 1);
 	return (iscprim(args[0]) ||
 			(iscvalue(args[0]) && cv_isPOD((cvalue_t*)ptr(args[0])))) ?
-		fl->FL_T : fl->FL_F;
+		FL(FL_T) : FL(FL_F);
 }
 
 static void
@@ -776,7 +776,7 @@
 {
 	cvinitfunc_t f = type->init;
 	if(f == nil)
-		lerrorf(fl->ArgError, "invalid c type");
+		lerrorf(FL(ArgError), "invalid c type");
 	f(type, v, dest);
 }
 
@@ -897,7 +897,7 @@
 	symbol_t *name = tosymbol(args[0]);
 	cvalue_t *cv;
 	if(ismanaged(args[0]) || (cv = name->dlcache) == nil)
-		lerrorf(fl->ArgError, "function %s not found", name->name);
+		lerrorf(FL(ArgError), "function %s not found", name->name);
 	return tagptr(cv, TAG_CVALUE);
 }
 
@@ -906,7 +906,7 @@
 {
 	cvalue_t *cv;
 	cv = calloc(CVALUE_NWORDS, sizeof(*cv));
-	cv->type = fl->builtintype;
+	cv->type = FL(builtintype);
 	cv->data = &cv->_space[0];
 	cv->len = sizeof(value_t);
 	*(builtin_t*)cv->data = f;
@@ -913,7 +913,7 @@
 
 	value_t sym = symbol(name);
 	((symbol_t*)ptr(sym))->dlcache = cv;
-	ptrhash_put(&fl->reverse_dlsym_lookup_table, cv, (void*)sym);
+	ptrhash_put(&FL(reverse_dlsym_lookup_table), cv, (void*)sym);
 
 	return tagptr(cv, TAG_CVALUE);
 }
@@ -920,7 +920,7 @@
 
 #define cv_intern(tok) \
 	do{ \
-		fl->tok##sym = symbol(#tok); \
+		FL(tok##sym) = symbol(#tok); \
 	}while(0)
 
 #define ctor_cv_intern(tok, nt, ctype) \
@@ -927,9 +927,9 @@
 	do{ \
 		symbol_t *s; \
 		cv_intern(tok); \
-		set(fl->tok##sym, cbuiltin(#tok, fn_builtin_##tok)); \
+		set(FL(tok##sym), cbuiltin(#tok, fn_builtin_##tok)); \
 		if(valid_numtype(nt)){ \
-			s = ptr(fl->tok##sym); \
+			s = ptr(FL(tok##sym)); \
 			s->numtype = nt; \
 			s->size = sizeof(ctype); \
 			s->align = offsetof(struct{char c; ctype x;}, x); \
@@ -938,8 +938,8 @@
 
 #define mk_primtype(name, ctype) \
 	do{ \
-		fl->name##type = get_type(fl->name##sym); \
-		fl->name##type->init = cvalue_##ctype##_init; \
+		FL(name##type) = get_type(FL(name##sym)); \
+		FL(name##type)->init = cvalue_##ctype##_init; \
 	}while(0)
 
 #define RETURN_NUM_AS(var, type) return(mk_##type(var))
@@ -1306,7 +1306,7 @@
 _Noreturn void
 DivideByZeroError(void)
 {
-	lerrorf(fl->DivideError, "/: division by zero");
+	lerrorf(FL(DivideError), "/: division by zero");
 }
 
 value_t
@@ -1473,7 +1473,7 @@
 	}
 	}
 	assert(0);
-	return fl->NIL;
+	return FL(NIL);
 }
 
 BUILTIN("logand", logand)
@@ -1611,10 +1611,10 @@
 void
 cvalues_init(void)
 {
-	htable_new(&fl->TypeTable, 256);
-	htable_new(&fl->reverse_dlsym_lookup_table, 256);
+	htable_new(&FL(TypeTable), 256);
+	htable_new(&FL(reverse_dlsym_lookup_table), 256);
 
-	fl->builtintype = define_opaque_type(fl->builtinsym, sizeof(builtin_t), nil, nil);
+	FL(builtintype) = define_opaque_type(FL(builtinsym), sizeof(builtin_t), nil, nil);
 
 	ctor_cv_intern(int8, T_INT8, int8_t);
 	ctor_cv_intern(uint8, T_UINT8, uint8_t);
@@ -1642,13 +1642,13 @@
 	cv_intern(struct);
 	cv_intern(union);
 	cv_intern(void);
-	fl->cfunctionsym = symbol("c-function");
+	FL(cfunctionsym) = symbol("c-function");
 
-	fl->stringtypesym = symbol("*string-type*");
-	setc(fl->stringtypesym, fl_list2(fl->arraysym, fl->bytesym));
+	FL(stringtypesym) = symbol("*string-type*");
+	setc(FL(stringtypesym), fl_list2(FL(arraysym), FL(bytesym)));
 
-	fl->runestringtypesym = symbol("*runestring-type*");
-	setc(fl->runestringtypesym, fl_list2(fl->arraysym, fl->runesym));
+	FL(runestringtypesym) = symbol("*runestring-type*");
+	setc(FL(runestringtypesym), fl_list2(FL(arraysym), FL(runesym)));
 
 	mk_primtype(int8, int8_t);
 	mk_primtype(uint8, uint8_t);
@@ -1671,13 +1671,13 @@
 	mk_primtype(double, double);
 
 	ctor_cv_intern(bignum, T_MPINT, mpint*);
-	fl->mpinttype = get_type(fl->bignumsym);
-	fl->mpinttype->init = cvalue_mpint_init;
-	fl->mpinttype->vtable = &mpint_vtable;
+	FL(mpinttype) = get_type(FL(bignumsym));
+	FL(mpinttype)->init = cvalue_mpint_init;
+	FL(mpinttype)->vtable = &mpint_vtable;
 
-	fl->stringtype = get_type(symbol_value(fl->stringtypesym));
-	fl->runestringtype = get_type(symbol_value(fl->runestringtypesym));
+	FL(stringtype) = get_type(symbol_value(FL(stringtypesym)));
+	FL(runestringtype) = get_type(symbol_value(FL(runestringtypesym)));
 
-	fl->emptystringsym = symbol("*empty-string*");
-	setc(fl->emptystringsym, cvalue_static_cstring(""));
+	FL(emptystringsym) = symbol("*empty-string*");
+	setc(FL(emptystringsym), cvalue_static_cstring(""));
 }
--- a/equal.c
+++ b/equal.c
@@ -23,7 +23,7 @@
 {
 	value_t c = (value_t)ptrhash_get(table, (void*)key);
 	if(c == (value_t)HT_NOTFOUND)
-		return fl->NIL;
+		return FL(NIL);
 	if(c == key)
 		return c;
 	return eq_class(table, c);
@@ -32,8 +32,8 @@
 static void
 eq_union(htable_t *table, value_t a, value_t b, value_t c, value_t cb)
 {
-	value_t ca = c == fl->NIL ? a : c;
-	if(cb != fl->NIL)
+	value_t ca = c == FL(NIL) ? a : c;
+	if(cb != FL(NIL))
 		ptrhash_put(table, (void*)cb, (void*)ca);
 	ptrhash_put(table, (void*)a, (void*)ca);
 	ptrhash_put(table, (void*)b, (void*)ca);
@@ -53,7 +53,7 @@
 	m = la < lb ? la : lb;
 	for(i = 0; i < m; i++){
 		value_t d = bounded_compare(vector_elt(a, i), vector_elt(b, i), bound-1, eq);
-		if(d == fl->NIL || numval(d) != 0)
+		if(d == FL(NIL) || numval(d) != 0)
 			return d;
 	}
 	if(la < lb)
@@ -75,7 +75,7 @@
 	if(a == b)
 		return fixnum(0);
 	if(bound <= 0)
-		return fl->NIL;
+		return FL(NIL);
 	int taga = tag(a);
 	int tagb = cmptag(b);
 	int c;
@@ -85,7 +85,7 @@
 		if(isfixnum(b))
 			return (numval(a) < numval(b)) ? fixnum(-1) : fixnum(1);
 		if(iscprim(b)){
-			if(cp_class((cprim_t*)ptr(b)) == fl->runetype)
+			if(cp_class((cprim_t*)ptr(b)) == FL(runetype))
 				return fixnum(1);
 			return fixnum(numeric_compare(a, b, eq, 1, 0));
 		}
@@ -106,10 +106,10 @@
 			return bounded_vector_compare(a, b, bound, eq);
 		break;
 	case TAG_CPRIM:
-		if(cp_class((cprim_t*)ptr(a)) == fl->runetype){
-			if(!iscprim(b) || cp_class(ptr(b)) != fl->runetype)
+		if(cp_class((cprim_t*)ptr(a)) == FL(runetype)){
+			if(!iscprim(b) || cp_class(ptr(b)) != FL(runetype))
 				return fixnum(-1);
-		}else if(iscprim(b) && cp_class(ptr(b)) == fl->runetype)
+		}else if(iscprim(b) && cp_class(ptr(b)) == FL(runetype))
 			return fixnum(1);
 		c = numeric_compare(a, b, eq, 1, 0);
 		if(c != 2)
@@ -133,13 +133,13 @@
 				function_t *fa = ptr(a);
 				function_t *fb = ptr(b);
 				d = bounded_compare(fa->bcode, fb->bcode, bound-1, eq);
-				if(d == fl->NIL || numval(d) != 0)
+				if(d == FL(NIL) || numval(d) != 0)
 					return d;
 				d = bounded_compare(fa->vals, fb->vals, bound-1, eq);
-				if(d == fl->NIL || numval(d) != 0)
+				if(d == FL(NIL) || numval(d) != 0)
 					return d;
 				d = bounded_compare(fa->env, fb->env, bound-1, eq);
-				if(d == fl->NIL || numval(d) != 0)
+				if(d == FL(NIL) || numval(d) != 0)
 					return d;
 				return fixnum(0);
 			}
@@ -150,7 +150,7 @@
 		if(tagb < TAG_CONS)
 			return fixnum(1);
 		d = bounded_compare(car_(a), car_(b), bound-1, eq);
-		if(d == fl->NIL || numval(d) != 0)
+		if(d == FL(NIL) || numval(d) != 0)
 			return d;
 		a = cdr_(a); b = cdr_(b);
 		bound--;
@@ -176,7 +176,7 @@
 		xb = vector_elt(b, i);
 		if(leafp(xa) || leafp(xb)){
 			d = bounded_compare(xa, xb, 1, eq);
-			if(d != fl->NIL && numval(d) != 0)
+			if(d != FL(NIL) && numval(d) != 0)
 				return d;
 		}else if(tag(xa) < tag(xb))
 			return fixnum(-1);
@@ -186,7 +186,7 @@
 
 	ca = eq_class(table, a);
 	cb = eq_class(table, b);
-	if(ca != fl->NIL && ca == cb)
+	if(ca != FL(NIL) && ca == cb)
 		return fixnum(0);
 
 	eq_union(table, a, b, ca, cb);
@@ -227,7 +227,7 @@
 			int tagdb = tag(db);
 			if(leafp(aa) || leafp(ab)){
 				d = bounded_compare(aa, ab, 1, eq);
-				if(d != fl->NIL && numval(d) != 0)
+				if(d != FL(NIL) && numval(d) != 0)
 					return d;
 			}
 			if(tagaa < tagab)
@@ -236,7 +236,7 @@
 				return fixnum(1);
 			if(leafp(da) || leafp(db)){
 				d = bounded_compare(da, db, 1, eq);
-				if(d != fl->NIL && numval(d) != 0)
+				if(d != FL(NIL) && numval(d) != 0)
 					return d;
 			}
 			if(tagda < tagdb)
@@ -246,7 +246,7 @@
 
 			ca = eq_class(table, a);
 			cb = eq_class(table, b);
-			if(ca != fl->NIL && ca == cb)
+			if(ca != FL(NIL) && ca == cb)
 				return fixnum(0);
 
 			eq_union(table, a, b, ca, cb);
@@ -271,7 +271,7 @@
 
 		ca = eq_class(table, a);
 		cb = eq_class(table, b);
-		if(ca != fl->NIL && ca == cb)
+		if(ca != FL(NIL) && ca == cb)
 			return fixnum(0);
 
 		eq_union(table, a, b, ca, cb);
@@ -298,7 +298,7 @@
 compare_(value_t a, value_t b, int eq)
 {
 	value_t guess = bounded_compare(a, b, BOUNDED_COMPARE_BOUND, eq);
-	if(guess == fl->NIL){
+	if(guess == FL(NIL)){
 		guess = cyc_compare(a, b, &equal_eq_hashtable, eq);
 		htable_reset(&equal_eq_hashtable, 512);
 	}
@@ -315,8 +315,8 @@
 fl_equal(value_t a, value_t b)
 {
 	if(eq_comparable(a, b))
-		return a == b ? fl->FL_T : fl->FL_F;
-	return numval(compare_(a, b, 1)) == 0 ? fl->FL_T : fl->FL_F;
+		return a == b ? FL(FL_T) : FL(FL_F);
+	return numval(compare_(a, b, 1)) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 /*
@@ -366,7 +366,7 @@
 	case TAG_CPRIM:
 		cp = ptr(a);
 		data = cp_data(cp);
-		if(cp_class(cp) == fl->runetype)
+		if(cp_class(cp) == FL(runetype))
 			return inthash(*(Rune*)data);
 		nt = cp_numtype(cp);
 		u.d = conv_to_double(data, nt);
@@ -374,7 +374,7 @@
 	case TAG_CVALUE:
 		cv = (cvalue_t*)ptr(a);
 		data = cv_data(cv);
-		if(cv->type == fl->mpinttype){
+		if(cv->type == FL(mpinttype)){
 			len = mptobe(*(mpint**)data, nil, 0, (uint8_t**)&data);
 			h = memhash(data, len);
 			LLT_FREE(data);
--- a/flisp.c
+++ b/flisp.c
@@ -25,7 +25,7 @@
 	builtin_t fptr;
 }builtinspec_t;
 
-__thread Fl *fl;
+Fl fl;
 
 int
 isbuiltin(value_t x)
@@ -48,7 +48,7 @@
 _Noreturn void
 fl_exit(int status)
 {
-	fl->exiting = true;
+	FL(exiting) = true;
 	gc(0);
 	exit(status);
 }
@@ -55,13 +55,13 @@
 
 #define FL_TRY \
 	fl_exception_context_t _ctx; int l__tr, l__ca; \
-	_ctx.sp = fl->SP; _ctx.frame = fl->curr_frame; _ctx.rdst = fl->readstate; _ctx.prev = fl->exctx; \
-	_ctx.ngchnd = fl->N_GCHND; fl->exctx = &_ctx; \
+	_ctx.sp = FL(SP); _ctx.frame = FL(curr_frame); _ctx.rdst = FL(readstate); _ctx.prev = FL(exctx); \
+	_ctx.ngchnd = FL(N_GCHND); FL(exctx) = &_ctx; \
 	if(!setjmp(_ctx.buf)) \
-		for(l__tr = 1; l__tr; l__tr = 0, (void)(fl->exctx = fl->exctx->prev))
+		for(l__tr = 1; l__tr; l__tr = 0, (void)(FL(exctx) = FL(exctx)->prev))
 
 #define FL_CATCH_INC \
-	l__ca = 0, fl->lasterror = fl->FL_NIL, fl->throwing_frame = 0, fl->SP = _ctx.sp, fl->curr_frame = _ctx.frame
+	l__ca = 0, FL(lasterror) = FL(FL_NIL), FL(throwing_frame) = 0, FL(SP) = _ctx.sp, FL(curr_frame) = _ctx.frame
 
 #define FL_CATCH \
 	else \
@@ -74,37 +74,37 @@
 void
 fl_savestate(fl_exception_context_t *_ctx)
 {
-	_ctx->sp = fl->SP;
-	_ctx->frame = fl->curr_frame;
-	_ctx->rdst = fl->readstate;
-	_ctx->prev = fl->exctx;
-	_ctx->ngchnd = fl->N_GCHND;
+	_ctx->sp = FL(SP);
+	_ctx->frame = FL(curr_frame);
+	_ctx->rdst = FL(readstate);
+	_ctx->prev = FL(exctx);
+	_ctx->ngchnd = FL(N_GCHND);
 }
 
 void
 fl_restorestate(fl_exception_context_t *_ctx)
 {
-	fl->lasterror = fl->FL_NIL;
-	fl->throwing_frame = 0;
-	fl->SP = _ctx->sp;
-	fl->curr_frame = _ctx->frame;
+	FL(lasterror) = FL(FL_NIL);
+	FL(throwing_frame) = 0;
+	FL(SP) = _ctx->sp;
+	FL(curr_frame) = _ctx->frame;
 }
 
 _Noreturn void
 fl_raise(value_t e)
 {
-	fl->lasterror = e;
+	FL(lasterror) = e;
 	// unwind read state
-	while(fl->readstate != fl->exctx->rdst){
-		free_readstate(fl->readstate);
-		fl->readstate = fl->readstate->prev;
+	while(FL(readstate) != FL(exctx)->rdst){
+		free_readstate(FL(readstate));
+		FL(readstate) = FL(readstate)->prev;
 	}
-	if(fl->throwing_frame == 0)
-		fl->throwing_frame = fl->curr_frame;
-	fl->N_GCHND = fl->exctx->ngchnd;
-	fl_exception_context_t *thisctx = fl->exctx;
-	if(fl->exctx->prev)   // don't throw past toplevel
-		fl->exctx = fl->exctx->prev;
+	if(FL(throwing_frame) == 0)
+		FL(throwing_frame) = FL(curr_frame);
+	FL(N_GCHND) = FL(exctx)->ngchnd;
+	fl_exception_context_t *thisctx = FL(exctx);
+	if(FL(exctx)->prev)   // don't throw past toplevel
+		FL(exctx) = FL(exctx)->prev;
 	longjmp(thisctx->buf, 1);
 }
 
@@ -127,19 +127,19 @@
 _Noreturn void
 type_error(char *expected, value_t got)
 {
-	fl_raise(fl_listn(3, fl->TypeError, symbol(expected), got));
+	fl_raise(fl_listn(3, FL(TypeError), symbol(expected), got));
 }
 
 _Noreturn void
 bounds_error(value_t arr, value_t ind)
 {
-	fl_raise(fl_listn(3, fl->BoundsError, arr, ind));
+	fl_raise(fl_listn(3, FL(BoundsError), arr, ind));
 }
 
 _Noreturn void
 unbound_error(value_t sym)
 {
-	fl_raise(fl_listn(2, fl->UnboundError, sym));
+	fl_raise(fl_listn(2, FL(UnboundError), sym));
 }
 
 // safe cast operators --------------------------------------------------------
@@ -202,7 +202,7 @@
 {
 	symbol_t **pnode;
 
-	pnode = symtab_lookup(&fl->symtab, str);
+	pnode = symtab_lookup(&FL(symtab), str);
 	if(*pnode == nil)
 		*pnode = mk_symbol(str);
 	return tagptr(*pnode, TAG_SYM);
@@ -213,7 +213,7 @@
 	argcount(nargs, 0);
 	USED(args);
 	gensym_t *gs = alloc_words(sizeof(gensym_t)/sizeof(void*));
-	gs->id = fl->_gensym_ctr++;
+	gs->id = FL(_gensym_ctr)++;
 	gs->binding = UNBOUND;
 	gs->isconst = 0;
 	gs->type = nil;
@@ -229,7 +229,7 @@
 BUILTIN("gensym?", gensymp)
 {
 	argcount(nargs, 1);
-	return isgensym(args[0]) ? fl->FL_T : fl->FL_F;
+	return isgensym(args[0]) ? FL(FL_T) : FL(FL_F);
 }
 
 char *
@@ -258,8 +258,8 @@
 {
 	if(ismanaged(v)){
 		gensym_t *gs = (gensym_t*)ptr(v);
-		fl->gsnameno = 1-fl->gsnameno;
-		char *n = uint2str(fl->gsname[fl->gsnameno]+1, sizeof(fl->gsname[0])-1, gs->id, 10);
+		FL(gsnameno) = 1-FL(gsnameno);
+		char *n = uint2str(FL(gsname)[FL(gsnameno)]+1, sizeof(FL(gsname)[0])-1, gs->id, 10);
 		*(--n) = 'g';
 		return n;
 	}
@@ -273,10 +273,10 @@
 {
 	cons_t *c;
 
-	if(__unlikely(fl->curheap > fl->lim))
+	if(__unlikely(FL(curheap) > FL(lim)))
 		gc(0);
-	c = (cons_t*)fl->curheap;
-	fl->curheap += sizeof(cons_t);
+	c = (cons_t*)FL(curheap);
+	FL(curheap) += sizeof(cons_t);
 	return tagptr(c, TAG_CONS);
 }
 
@@ -287,13 +287,13 @@
 
 	assert(n > 0);
 	n = LLT_ALIGN(n, 2);   // only allocate multiples of 2 words
-	if(__unlikely((value_t*)fl->curheap > ((value_t*)fl->lim)+2-n)){
+	if(__unlikely((value_t*)FL(curheap) > ((value_t*)FL(lim))+2-n)){
 		gc(0);
-		while((value_t*)fl->curheap > ((value_t*)fl->lim)+2-n)
+		while((value_t*)FL(curheap) > ((value_t*)FL(lim))+2-n)
 			gc(1);
 	}
-	first = (value_t*)fl->curheap;
-	fl->curheap += (n*sizeof(value_t));
+	first = (value_t*)FL(curheap);
+	FL(curheap) += (n*sizeof(value_t));
 	return first;
 }
 
@@ -301,7 +301,7 @@
 alloc_vector(size_t n, int init)
 {
 	if(n == 0)
-		return fl->the_empty_vector;
+		return FL(the_empty_vector);
 	value_t *c = alloc_words(n+1);
 	value_t v = tagptr(c, TAG_VECTOR);
 	vector_setsize(v, n);
@@ -308,7 +308,7 @@
 	if(init){
 		unsigned int i;
 		for(i = 0; i < n; i++)
-			vector_elt(v, i) = fl->FL_UNSPECIFIED;
+			vector_elt(v, i) = FL(FL_UNSPECIFIED);
 	}
 	return v;
 }
@@ -318,16 +318,16 @@
 void
 fl_gc_handle(value_t *pv)
 {
-	if(__unlikely(fl->N_GCHND >= N_GC_HANDLES))
-		lerrorf(fl->MemoryError, "out of gc handles");
-	fl->GCHandleStack[fl->N_GCHND++] = pv;
+	if(__unlikely(FL(N_GCHND) >= N_GC_HANDLES))
+		lerrorf(FL(MemoryError), "out of gc handles");
+	FL(GCHandleStack)[FL(N_GCHND)++] = pv;
 }
 
 void
 fl_free_gc_handles(uint32_t n)
 {
-	assert(fl->N_GCHND >= n);
-	fl->N_GCHND -= n;
+	assert(FL(N_GCHND) >= n);
+	FL(N_GCHND) -= n;
 }
 
 value_t
@@ -344,8 +344,8 @@
 				*pcdr = cdr_(v);
 				return first;
 			}
-			*pcdr = nc = tagptr((cons_t*)fl->curheap, TAG_CONS);
-			fl->curheap += sizeof(cons_t);
+			*pcdr = nc = tagptr((cons_t*)FL(curheap), TAG_CONS);
+			FL(curheap) += sizeof(cons_t);
 			d = cdr_(v);
 			car_(v) = TAG_FWD;
 			cdr_(v) = nc;
@@ -353,7 +353,7 @@
 			pcdr = &cdr_(nc);
 			v = d;
 		}while(iscons(v));
-		*pcdr = d == fl->NIL ? fl->NIL : relocate(d);
+		*pcdr = d == FL(NIL) ? FL(NIL) : relocate(d);
 		return first;
 	}
 
@@ -449,32 +449,32 @@
 	uint32_t i, f, top;
 	fl_readstate_t *rs;
 
-	fl->curheap = fl->tospace;
-	if(fl->grew)
-		fl->lim = fl->curheap+fl->heapsize*2-sizeof(cons_t);
+	FL(curheap) = FL(tospace);
+	if(FL(grew))
+		FL(lim) = FL(curheap)+FL(heapsize)*2-sizeof(cons_t);
 	else
-		fl->lim = fl->curheap+fl->heapsize-sizeof(cons_t);
+		FL(lim) = FL(curheap)+FL(heapsize)-sizeof(cons_t);
 
-	if(fl->throwing_frame > fl->curr_frame){
-		top = fl->throwing_frame - 4;
-		f = fl->Stack[fl->throwing_frame-4];
+	if(FL(throwing_frame) > FL(curr_frame)){
+		top = FL(throwing_frame) - 4;
+		f = FL(Stack)[FL(throwing_frame)-4];
 	}else{
-		top = fl->SP;
-		f = fl->curr_frame;
+		top = FL(SP);
+		f = FL(curr_frame);
 	}
 	while(1){
 		for(i = f; i < top; i++)
-			fl->Stack[i] = relocate(fl->Stack[i]);
+			FL(Stack)[i] = relocate(FL(Stack)[i]);
 		if(f == 0)
 			break;
 		top = f - 4;
-		f = fl->Stack[f-4];
+		f = FL(Stack)[f-4];
 	}
-	for(i = 0; i < fl->N_GCHND; i++)
-		*fl->GCHandleStack[i] = relocate(*fl->GCHandleStack[i]);
-	trace_globals(fl->symtab);
+	for(i = 0; i < FL(N_GCHND); i++)
+		*FL(GCHandleStack)[i] = relocate(*FL(GCHandleStack)[i]);
+	trace_globals(FL(symtab));
 	relocate_typetable();
-	rs = fl->readstate;
+	rs = FL(readstate);
 	while(rs){
 		value_t ent;
 		for(i = 0; i < rs->backrefs.size; i++){
@@ -490,38 +490,38 @@
 		rs->source = relocate(rs->source);
 		rs = rs->prev;
 	}
-	fl->lasterror = relocate(fl->lasterror);
-	fl->memory_exception_value = relocate(fl->memory_exception_value);
-	fl->the_empty_vector = relocate(fl->the_empty_vector);
+	FL(lasterror) = relocate(FL(lasterror));
+	FL(memory_exception_value) = relocate(FL(memory_exception_value));
+	FL(the_empty_vector) = relocate(FL(the_empty_vector));
 
 	sweep_finalizers();
 
 #ifdef VERBOSEGC
 	printf("GC: found %d/%d live conses\n",
-		   (fl->curheap-fl->tospace)/sizeof(cons_t), fl->heapsize/sizeof(cons_t));
+		   (FL(curheap)-FL(tospace))/sizeof(cons_t), FL(heapsize)/sizeof(cons_t));
 #endif
-	temp = fl->tospace;
-	fl->tospace = fl->fromspace;
-	fl->fromspace = temp;
+	temp = FL(tospace);
+	FL(tospace) = FL(fromspace);
+	FL(fromspace) = temp;
 
 	// if we're using > 80% of the space, resize tospace so we have
 	// more space to fill next time. if we grew tospace last time,
 	// grow the other half of the heap this time to catch up.
-	if(fl->grew || ((fl->lim-fl->curheap) < (int)(fl->heapsize/5)) || mustgrow){
-		temp = LLT_REALLOC(fl->tospace, fl->heapsize*2);
+	if(FL(grew) || ((FL(lim)-FL(curheap)) < (int)(FL(heapsize)/5)) || mustgrow){
+		temp = LLT_REALLOC(FL(tospace), FL(heapsize)*2);
 		if(__unlikely(temp == nil))
-			fl_raise(fl->memory_exception_value);
-		fl->tospace = temp;
-		if(fl->grew){
-			fl->heapsize *= 2;
-			temp = bitvector_resize(fl->consflags, 0, fl->heapsize/sizeof(cons_t), 1);
+			fl_raise(FL(memory_exception_value));
+		FL(tospace) = temp;
+		if(FL(grew)){
+			FL(heapsize) *= 2;
+			temp = bitvector_resize(FL(consflags), 0, FL(heapsize)/sizeof(cons_t), 1);
 			if(__unlikely(temp == nil))
-				fl_raise(fl->memory_exception_value);
-			fl->consflags = (uint32_t*)temp;
+				fl_raise(FL(memory_exception_value));
+			FL(consflags) = (uint32_t*)temp;
 		}
-		fl->grew = !fl->grew;
+		FL(grew) = !FL(grew);
 	}
-	if(fl->curheap > fl->lim)  // all data was live
+	if(FL(curheap) > FL(lim))  // all data was live
 		gc(0);
 }
 
@@ -528,12 +528,12 @@
 static void
 grow_stack(void)
 {
-	size_t newsz = fl->N_STACK * 2;
-	value_t *ns = LLT_REALLOC(fl->Stack, newsz*sizeof(value_t));
+	size_t newsz = FL(N_STACK) * 2;
+	value_t *ns = LLT_REALLOC(FL(Stack), newsz*sizeof(value_t));
 	if(__unlikely(ns == nil))
-		lerrorf(fl->MemoryError, "stack overflow");
-	fl->Stack = ns;
-	fl->N_STACK = newsz;
+		lerrorf(FL(MemoryError), "stack overflow");
+	FL(Stack) = ns;
+	FL(N_STACK) = newsz;
 }
 
 // utils ----------------------------------------------------------------------
@@ -542,23 +542,23 @@
 static value_t
 _applyn(uint32_t n)
 {
-	value_t f = fl->Stack[fl->SP-n-1];
-	uint32_t saveSP = fl->SP;
+	value_t f = FL(Stack)[FL(SP)-n-1];
+	uint32_t saveSP = FL(SP);
 	value_t v;
 	if(iscbuiltin(f)){
-		v = ((builtin_t*)ptr(f))[3](&fl->Stack[fl->SP-n], n);
+		v = ((builtin_t*)ptr(f))[3](&FL(Stack)[FL(SP)-n], n);
 	}else if(isfunction(f)){
 		v = apply_cl(n);
 	}else if(__likely(isbuiltin(f))){
-		value_t tab = symbol_value(fl->builtins_table_sym);
+		value_t tab = symbol_value(FL(builtins_table_sym));
 		if(__unlikely(ptr(tab) == nil))
 			unbound_error(tab);
-		fl->Stack[fl->SP-n-1] = vector_elt(tab, uintval(f));
+		FL(Stack)[FL(SP)-n-1] = vector_elt(tab, uintval(f));
 		v = apply_cl(n);
 	}else{
 		type_error("function", f);
 	}
-	fl->SP = saveSP;
+	FL(SP) = saveSP;
 	return v;
 }
 
@@ -566,16 +566,16 @@
 fl_apply(value_t f, value_t l)
 {
 	value_t v = l;
-	uint32_t n = fl->SP;
+	uint32_t n = FL(SP);
 
 	PUSH(f);
 	while(iscons(v)){
-		if(fl->SP >= fl->N_STACK)
+		if(FL(SP) >= FL(N_STACK))
 			grow_stack();
 		PUSH(car_(v));
 		v = cdr_(v);
 	}
-	n = fl->SP - n - 1;
+	n = FL(SP) - n - 1;
 	v = _applyn(n);
 	POPN(n+1);
 	return v;
@@ -589,7 +589,7 @@
 	size_t i;
 
 	PUSH(f);
-	while(fl->SP+n >= fl->N_STACK)
+	while(FL(SP)+n >= FL(N_STACK))
 		grow_stack();
 	for(i = 0; i < n; i++){
 		value_t a = va_arg(ap, value_t);
@@ -606,10 +606,10 @@
 {
 	va_list ap;
 	va_start(ap, n);
-	uint32_t si = fl->SP;
+	uint32_t si = FL(SP);
 	size_t i;
 
-	while(fl->SP+n >= fl->N_STACK)
+	while(FL(SP)+n >= FL(N_STACK))
 		grow_stack();
 	for(i = 0; i < n; i++){
 		value_t a = va_arg(ap, value_t);
@@ -618,11 +618,11 @@
 	cons_t *c = alloc_words(n*2);
 	cons_t *l = c;
 	for(i = 0; i < n; i++){
-		c->car = fl->Stack[si++];
+		c->car = FL(Stack)[si++];
 		c->cdr = tagptr(c+1, TAG_CONS);
 		c++;
 	}
-	c[-1].cdr = fl->NIL;
+	c[-1].cdr = FL(NIL);
 
 	POPN(n);
 	va_end(ap);
@@ -640,7 +640,7 @@
 	c[0].car = a;
 	c[0].cdr = tagptr(c+1, TAG_CONS);
 	c[1].car = b;
-	c[1].cdr = fl->NIL;
+	c[1].cdr = FL(NIL);
 	return tagptr(c, TAG_CONS);
 }
 
@@ -662,7 +662,7 @@
 		return 1;
 	if(iscprim(v)){
 		cprim_t *c = ptr(v);
-		return c->type != fl->runetype;
+		return c->type != FL(runetype);
 	}
 	if(iscvalue(v)){
 		cvalue_t *c = ptr(v);
@@ -689,7 +689,7 @@
 	if(star)
 		c[-2].cdr = c[-1].car;
 	else
-		c[-1].cdr = fl->NIL;
+		c[-1].cdr = FL(NIL);
 	return v;
 }
 
@@ -697,21 +697,21 @@
 copy_list(value_t L)
 {
 	if(!iscons(L))
-		return fl->NIL;
-	PUSH(fl->NIL);
+		return FL(NIL);
+	PUSH(FL(NIL));
 	PUSH(L);
-	value_t *plcons = &fl->Stack[fl->SP-2];
-	value_t *pL = &fl->Stack[fl->SP-1];
+	value_t *plcons = &FL(Stack)[FL(SP)-2];
+	value_t *pL = &FL(Stack)[FL(SP)-1];
 	value_t c;
 	c = mk_cons(); PUSH(c);  // save first cons
 	car_(c) = car_(*pL);
-	cdr_(c) = fl->NIL;
+	cdr_(c) = FL(NIL);
 	*plcons = c;
 	*pL = cdr_(*pL);
 	while(iscons(*pL)){
 		c = mk_cons();
 		car_(c) = car_(*pL);
-		cdr_(c) = fl->NIL;
+		cdr_(c) = FL(NIL);
 		cdr_(*plcons) = c;
 		*plcons = c;
 		*pL = cdr_(*pL);
@@ -724,22 +724,22 @@
 static value_t
 do_trycatch(void)
 {
-	uint32_t saveSP = fl->SP;
-	value_t v = fl->NIL;
-	value_t thunk = fl->Stack[fl->SP-2];
-	fl->Stack[fl->SP-2] = fl->Stack[fl->SP-1];
-	fl->Stack[fl->SP-1] = thunk;
+	uint32_t saveSP = FL(SP);
+	value_t v = FL(NIL);
+	value_t thunk = FL(Stack)[FL(SP)-2];
+	FL(Stack)[FL(SP)-2] = FL(Stack)[FL(SP)-1];
+	FL(Stack)[FL(SP)-1] = thunk;
 
 	FL_TRY{
 		v = apply_cl(0);
 	}
 	FL_CATCH{
-		v = fl->Stack[saveSP-2];
+		v = FL(Stack)[saveSP-2];
 		PUSH(v);
-		PUSH(fl->lasterror);
+		PUSH(FL(lasterror));
 		v = apply_cl(1);
 	}
-	fl->SP = saveSP;
+	FL(SP) = saveSP;
 	return v;
 }
 
@@ -752,20 +752,20 @@
 {
 	uint32_t extr = nopt+nkw;
 	uint32_t ntot = nreq+extr;
-	value_t args[64], v = fl->NIL;
+	value_t args[64], v = FL(NIL);
 	uint32_t i, a = 0, nrestargs;
-	value_t s1 = fl->Stack[fl->SP-1];
-	value_t s2 = fl->Stack[fl->SP-2];
-	value_t s4 = fl->Stack[fl->SP-4];
-	value_t s5 = fl->Stack[fl->SP-5];
+	value_t s1 = FL(Stack)[FL(SP)-1];
+	value_t s2 = FL(Stack)[FL(SP)-2];
+	value_t s4 = FL(Stack)[FL(SP)-4];
+	value_t s5 = FL(Stack)[FL(SP)-5];
 	if(__unlikely(nargs < nreq))
-		lerrorf(fl->ArgError, "too few arguments");
+		lerrorf(FL(ArgError), "too few arguments");
 	if(__unlikely(extr > nelem(args)))
-		lerrorf(fl->ArgError, "too many arguments");
+		lerrorf(FL(ArgError), "too many arguments");
 	for(i = 0; i < extr; i++)
 		args[i] = UNBOUND;
 	for(i = nreq; i < nargs; i++){
-		v = fl->Stack[bp+i];
+		v = FL(Stack)[bp+i];
 		if(issymbol(v) && iskeyword((symbol_t*)ptr(v)))
 			break;
 		if(a >= nopt)
@@ -779,7 +779,7 @@
 	do{
 		i++;
 		if(__unlikely(i >= nargs))
-			lerrorf(fl->ArgError, "keyword %s requires an argument", symbol_name(v));
+			lerrorf(FL(ArgError), "keyword %s requires an argument", symbol_name(v));
 		value_t hv = fixnum(((symbol_t*)ptr(v))->hash);
 		lltint_t lx = numval(hv);
 		uintptr_t x = 2*((lx < 0 ? -lx : lx) % n);
@@ -789,32 +789,32 @@
 			idx += nopt;
 			if(args[idx] == UNBOUND){
 				// if duplicate key, keep first value
-				args[idx] = fl->Stack[bp+i];
+				args[idx] = FL(Stack)[bp+i];
 			}
 		}else{
-			lerrorf(fl->ArgError, "unsupported keyword %s", symbol_name(v));
+			lerrorf(FL(ArgError), "unsupported keyword %s", symbol_name(v));
 		}
 		i++;
 		if(i >= nargs)
 			break;
-		v = fl->Stack[bp+i];
+		v = FL(Stack)[bp+i];
 	}while(issymbol(v) && iskeyword((symbol_t*)ptr(v)));
 no_kw:
 	nrestargs = nargs - i;
 	if(__unlikely(!va && nrestargs > 0))
-		lerrorf(fl->ArgError, "too many arguments");
+		lerrorf(FL(ArgError), "too many arguments");
 	nargs = ntot + nrestargs;
 	if(nrestargs)
-		memmove(&fl->Stack[bp+ntot], &fl->Stack[bp+i], nrestargs*sizeof(value_t));
-	memmove(&fl->Stack[bp+nreq], args, extr*sizeof(value_t));
-	fl->SP = bp + nargs;
-	assert(fl->SP < fl->N_STACK-5);
+		memmove(&FL(Stack)[bp+ntot], &FL(Stack)[bp+i], nrestargs*sizeof(value_t));
+	memmove(&FL(Stack)[bp+nreq], args, extr*sizeof(value_t));
+	FL(SP) = bp + nargs;
+	assert(FL(SP) < FL(N_STACK)-5);
 	PUSH(s5);
 	PUSH(s4);
 	PUSH(nargs);
 	PUSH(s2);
 	PUSH(s1);
-	fl->curr_frame = fl->SP;
+	FL(curr_frame) = FL(SP);
 	return nargs;
 }
 
@@ -855,7 +855,7 @@
 static value_t
 apply_cl(uint32_t nargs)
 {
-	uint32_t top_frame = fl->curr_frame;
+	uint32_t top_frame = FL(curr_frame);
 	// frame variables
 	uint32_t n, captured;
 	uint32_t bp;
@@ -876,42 +876,42 @@
 	USED(v);
 apply_cl_top:
 	captured = 0;
-	func = fl->Stack[fl->SP-nargs-1];
+	func = FL(Stack)[FL(SP)-nargs-1];
 	ip = cv_data((cvalue_t*)ptr(fn_bcode(func)));
 	assert(!ismanaged((uintptr_t)ip));
-	i = fl->SP+GET_INT32(ip);
-	while(i >= fl->N_STACK)
+	i = FL(SP)+GET_INT32(ip);
+	while(i >= FL(N_STACK))
 		grow_stack();
 	ip += 4;
 
-	bp = fl->SP-nargs;
+	bp = FL(SP)-nargs;
 	PUSH(fn_env(func));
-	PUSH(fl->curr_frame);
+	PUSH(FL(curr_frame));
 	PUSH(nargs);
-	ipd = fl->SP;
-	fl->SP++; // ip
+	ipd = FL(SP);
+	FL(SP)++; // ip
 	PUSH(0); // captured?
-	fl->curr_frame = fl->SP;
+	FL(curr_frame) = FL(SP);
 
 	op = *ip++;
 	while(1){
 		switch(op){
 		OP(OP_LOADA0)
-			PUSH(captured ? vector_elt(fl->Stack[bp], 0) : fl->Stack[bp]);
+			PUSH(captured ? vector_elt(FL(Stack)[bp], 0) : FL(Stack)[bp]);
 			NEXT_OP;
 
 		OP(OP_LOADA1)
-			PUSH(captured ? vector_elt(fl->Stack[bp], 1) : fl->Stack[bp+1]);
+			PUSH(captured ? vector_elt(FL(Stack)[bp], 1) : FL(Stack)[bp+1]);
 			NEXT_OP;
 
 		OP(OP_LOADV)
-			v = fn_vals(fl->Stack[bp-1]);
+			v = fn_vals(FL(Stack)[bp-1]);
 			assert(*ip < vector_size(v));
 			PUSH(vector_elt(v, *ip++));
 			NEXT_OP;
 
 		OP(OP_BRF)
-			ip += POP() == fl->FL_F ? GET_INT16(ip) : 2;
+			ip += POP() == FL(FL_F) ? GET_INT16(ip) : 2;
 			NEXT_OP;
 
 		OP(OP_POP)
@@ -936,15 +936,15 @@
 				n = *ip++;  // nargs
 			}
 		do_call:
-			fl->Stack[ipd] = (uintptr_t)ip;
-			func = fl->Stack[fl->SP-n-1];
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			func = FL(Stack)[FL(SP)-n-1];
 			if(tag(func) == TAG_FUNCTION){
 				if(func > (N_BUILTINS<<3)){
 					if(tail){
-						fl->curr_frame = fl->Stack[fl->curr_frame-4];
+						FL(curr_frame) = FL(Stack)[FL(curr_frame)-4];
 						for(s = -1; s < (fixnum_t)n; s++)
-							fl->Stack[bp+s] = fl->Stack[fl->SP-n+s];
-						fl->SP = bp+n;
+							FL(Stack)[bp+s] = FL(Stack)[FL(SP)-n+s];
+						FL(SP) = bp+n;
 					}
 					nargs = n;
 					goto apply_cl_top;
@@ -957,9 +957,9 @@
 						else if(s != ANYARGS && (signed)n < -s)
 							argcount(n, -s);
 						// remove function arg
-						for(s = fl->SP-n-1; s < (int)fl->SP-1; s++)
-							fl->Stack[s] = fl->Stack[s+1];
-						fl->SP--;
+						for(s = FL(SP)-n-1; s < (int)FL(SP)-1; s++)
+							FL(Stack)[s] = FL(Stack)[s+1];
+						FL(SP)--;
 						switch(i){
 						case OP_LIST:   goto apply_list;
 						case OP_VECTOR: goto apply_vector;
@@ -975,21 +975,21 @@
 					}
 				}
 			}else if(__likely(iscbuiltin(func))){
-				s = fl->SP;
-				v = (((builtin_t*)ptr(func))[3])(&fl->Stack[fl->SP-n], n);
-				fl->SP = s-n;
-				fl->Stack[fl->SP-1] = v;
+				s = FL(SP);
+				v = (((builtin_t*)ptr(func))[3])(&FL(Stack)[FL(SP)-n], n);
+				FL(SP) = s-n;
+				FL(Stack)[FL(SP)-1] = v;
 				NEXT_OP;
 			}
 			type_error("function", func);
 
 		OP(OP_LOADGL)
-			v = fn_vals(fl->Stack[bp-1]);
+			v = fn_vals(FL(Stack)[bp-1]);
 			v = vector_elt(v, GET_INT32(ip));
 			ip += 4;
 			if(0){
 		OP(OP_LOADG)
-				v = fn_vals(fl->Stack[bp-1]);
+				v = fn_vals(FL(Stack)[bp-1]);
 				assert(*ip < vector_size(v));
 				v = vector_elt(v, *ip);
 				ip++;
@@ -997,7 +997,7 @@
 			assert(issymbol(v));
 			sym = (symbol_t*)ptr(v);
 			if(__unlikely(sym->binding == UNBOUND)){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				unbound_error(v);
 			}
 			PUSH(sym->binding);
@@ -1007,12 +1007,12 @@
 			assert(nargs > 0);
 			i = *ip++;
 			if(captured){
-				e = fl->Stack[bp];
+				e = FL(Stack)[bp];
 				assert(isvector(e));
 				assert(i < vector_size(e));
 				v = vector_elt(e, i);
 			}else{
-				v = fl->Stack[bp+i];
+				v = FL(Stack)[bp+i];
 			}
 			PUSH(v);
 			NEXT_OP;
@@ -1020,7 +1020,7 @@
 		OP(OP_LOADC)
 			s = *ip++;
 			i = *ip++;
-			v = fl->Stack[bp+nargs];
+			v = FL(Stack)[bp+nargs];
 			while(s--)
 				v = vector_elt(v, vector_size(v)-1);
 			assert(isvector(v));
@@ -1030,40 +1030,40 @@
 
 		OP(OP_RET)
 			v = POP();
-			fl->SP = fl->curr_frame;
-			fl->curr_frame = fl->Stack[fl->SP-4];
-			if(fl->curr_frame == top_frame)
+			FL(SP) = FL(curr_frame);
+			FL(curr_frame) = FL(Stack)[FL(SP)-4];
+			if(FL(curr_frame) == top_frame)
 				return v;
-			fl->SP -= 5+nargs;
-			captured = fl->Stack[fl->curr_frame-1];
-			ipd = fl->curr_frame-2;
-			ip = (uint8_t*)fl->Stack[ipd];
-			nargs = fl->Stack[fl->curr_frame-3];
-			bp = fl->curr_frame - 5 - nargs;
-			fl->Stack[fl->SP-1] = v;
+			FL(SP) -= 5+nargs;
+			captured = FL(Stack)[FL(curr_frame)-1];
+			ipd = FL(curr_frame)-2;
+			ip = (uint8_t*)FL(Stack)[ipd];
+			nargs = FL(Stack)[FL(curr_frame)-3];
+			bp = FL(curr_frame) - 5 - nargs;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_DUP)
-			fl->SP++;
-			fl->Stack[fl->SP-1] = fl->Stack[fl->SP-2];
+			FL(SP)++;
+			FL(Stack)[FL(SP)-1] = FL(Stack)[FL(SP)-2];
 			NEXT_OP;
 
 		OP(OP_CAR)
-			v = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-1];
 			if(__unlikely(!iscons(v))){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			fl->Stack[fl->SP-1] = car_(v);
+			FL(Stack)[FL(SP)-1] = car_(v);
 			NEXT_OP;
 
 		OP(OP_CDR)
-			v = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-1];
 			if(__unlikely(!iscons(v))){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			fl->Stack[fl->SP-1] = cdr_(v);
+			FL(Stack)[FL(SP)-1] = cdr_(v);
 			NEXT_OP;
 
 		OP(OP_CLOSURE)
@@ -1076,41 +1076,41 @@
 				pv[0] = fixnum(n+1);
 				pv++;
 				do{
-					pv[n] = fl->Stack[bp+n];
+					pv[n] = FL(Stack)[bp+n];
 				}while(n--);
 				// environment representation changed; install
 				// the new representation so everybody can see it
 				captured = 1;
-				fl->Stack[fl->curr_frame-1] = 1;
-				fl->Stack[bp] = fl->Stack[fl->SP-1];
+				FL(Stack)[FL(curr_frame)-1] = 1;
+				FL(Stack)[bp] = FL(Stack)[FL(SP)-1];
 			}else{
-				PUSH(fl->Stack[bp]); // env has already been captured; share
+				PUSH(FL(Stack)[bp]); // env has already been captured; share
 			}
-			if(fl->curheap > fl->lim-2)
+			if(FL(curheap) > FL(lim)-2)
 				gc(0);
-			pv = (value_t*)fl->curheap;
-			fl->curheap += 4*sizeof(value_t);
-			e = fl->Stack[fl->SP-2];  // closure to copy
+			pv = (value_t*)FL(curheap);
+			FL(curheap) += 4*sizeof(value_t);
+			e = FL(Stack)[FL(SP)-2];  // closure to copy
 			assert(isfunction(e));
 			pv[0] = ((value_t*)ptr(e))[0];
 			pv[1] = ((value_t*)ptr(e))[1];
-			pv[2] = fl->Stack[fl->SP-1];  // env
+			pv[2] = FL(Stack)[FL(SP)-1];  // env
 			pv[3] = ((value_t*)ptr(e))[3];
 			POPN(1);
-			fl->Stack[fl->SP-1] = tagptr(pv, TAG_FUNCTION);
+			FL(Stack)[FL(SP)-1] = tagptr(pv, TAG_FUNCTION);
 			NEXT_OP;
 
 		OP(OP_SETA)
 			assert(nargs > 0);
-			v = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-1];
 			i = *ip++;
 			if(captured){
-				e = fl->Stack[bp];
+				e = FL(Stack)[bp];
 				assert(isvector(e));
 				assert(i < vector_size(e));
 				vector_elt(e, i) = v;
 			}else{
-				fl->Stack[bp+i] = v;
+				FL(Stack)[bp+i] = v;
 			}
 			NEXT_OP;
 
@@ -1119,20 +1119,20 @@
 			NEXT_OP;
 
 		OP(OP_LOADC00)
-			PUSH(vector_elt(fl->Stack[bp+nargs], 0));
+			PUSH(vector_elt(FL(Stack)[bp+nargs], 0));
 			NEXT_OP;
 
 		OP(OP_PAIRP)
-			fl->Stack[fl->SP-1] = iscons(fl->Stack[fl->SP-1]) ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = iscons(FL(Stack)[FL(SP)-1]) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_BRNE)
-			ip += fl->Stack[fl->SP-2] != fl->Stack[fl->SP-1] ? GET_INT16(ip) : 2;
+			ip += FL(Stack)[FL(SP)-2] != FL(Stack)[FL(SP)-1] ? GET_INT16(ip) : 2;
 			POPN(2);
 			NEXT_OP;
 
 		OP(OP_LOADT)
-			PUSH(fl->FL_T);
+			PUSH(FL(FL_T));
 			NEXT_OP;
 
 		OP(OP_LOAD0)
@@ -1140,37 +1140,37 @@
 			NEXT_OP;
 
 		OP(OP_LOADC01)
-			PUSH(vector_elt(fl->Stack[bp+nargs], 1));
+			PUSH(vector_elt(FL(Stack)[bp+nargs], 1));
 			NEXT_OP;
 
 		OP(OP_AREF)
-			fl->Stack[ipd] = (uintptr_t)ip;
-			v = fl->Stack[fl->SP-2];
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			v = FL(Stack)[FL(SP)-2];
 			if(isvector(v)){
-				e = fl->Stack[fl->SP-1];
+				e = FL(Stack)[FL(SP)-1];
 				i = isfixnum(e) ? numval(e) : (uint32_t)toulong(e);
 				if(__unlikely(i >= vector_size(v)))
 					bounds_error(v, e);
 				v = vector_elt(v, i);
 			}else if(__likely(isarray(v))){
-				v = cvalue_array_aref(&fl->Stack[fl->SP-2]);
+				v = cvalue_array_aref(&FL(Stack)[FL(SP)-2]);
 			}else{
 				type_error("sequence", v);
 			}
 			POPN(1);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_ATOMP)
-			fl->Stack[fl->SP-1] = iscons(fl->Stack[fl->SP-1]) ? fl->FL_F : fl->FL_T;
+			FL(Stack)[FL(SP)-1] = iscons(FL(Stack)[FL(SP)-1]) ? FL(FL_F) : FL(FL_T);
 			NEXT_OP;
 
 		OP(OP_BRT)
-			ip += POP() != fl->FL_F ? GET_INT16(ip) : 2;
+			ip += POP() != FL(FL_F) ? GET_INT16(ip) : 2;
 			NEXT_OP;
 
 		OP(OP_BRNN)
-			ip += POP() != fl->NIL ? GET_INT16(ip) : 2;
+			ip += POP() != FL(NIL) ? GET_INT16(ip) : 2;
 			NEXT_OP;
 
 		OP(OP_LOAD1)
@@ -1178,122 +1178,122 @@
 			NEXT_OP;
 
 		OP(OP_LT)
-			x = numeric_compare(fl->Stack[fl->SP-2], fl->Stack[fl->SP-1], 0, 0, 0);
+			x = numeric_compare(FL(Stack)[FL(SP)-2], FL(Stack)[FL(SP)-1], 0, 0, 0);
 			if(x > 1)
-				x = numval(fl_compare(fl->Stack[fl->SP-2], fl->Stack[fl->SP-1]));
+				x = numval(fl_compare(FL(Stack)[FL(SP)-2], FL(Stack)[FL(SP)-1]));
 			POPN(1);
-			fl->Stack[fl->SP-1] = x < 0 ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = x < 0 ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_ADD2)
-			fl->Stack[ipd] = (uintptr_t)ip;
-			if(bothfixnums(fl->Stack[fl->SP-1], fl->Stack[fl->SP-2])){
-				s = numval(fl->Stack[fl->SP-1]) + numval(fl->Stack[fl->SP-2]);
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			if(bothfixnums(FL(Stack)[FL(SP)-1], FL(Stack)[FL(SP)-2])){
+				s = numval(FL(Stack)[FL(SP)-1]) + numval(FL(Stack)[FL(SP)-2]);
 				v = fits_fixnum(s) ? fixnum(s) : mk_xlong(s);
 			}else{
-				v = fl_add_any(&fl->Stack[fl->SP-2], 2, 0);
+				v = fl_add_any(&FL(Stack)[FL(SP)-2], 2, 0);
 			}
 			POPN(1);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_SETCDR)
-			v = fl->Stack[fl->SP-2];
+			v = FL(Stack)[FL(SP)-2];
 			if(__unlikely(!iscons(v))){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			cdr_(v) = fl->Stack[fl->SP-1];
+			cdr_(v) = FL(Stack)[FL(SP)-1];
 			POPN(1);
 			NEXT_OP;
 
 		OP(OP_LOADF)
-			PUSH(fl->FL_F);
+			PUSH(FL(FL_F));
 			NEXT_OP;
 
 		OP(OP_CONS)
-			if(fl->curheap > fl->lim)
+			if(FL(curheap) > FL(lim))
 				gc(0);
-			c = (cons_t*)fl->curheap;
-			fl->curheap += sizeof(cons_t);
-			c->car = fl->Stack[fl->SP-2];
-			c->cdr = fl->Stack[fl->SP-1];
-			fl->Stack[fl->SP-2] = tagptr(c, TAG_CONS);
+			c = (cons_t*)FL(curheap);
+			FL(curheap) += sizeof(cons_t);
+			c->car = FL(Stack)[FL(SP)-2];
+			c->cdr = FL(Stack)[FL(SP)-1];
+			FL(Stack)[FL(SP)-2] = tagptr(c, TAG_CONS);
 			POPN(1);
 			NEXT_OP;
 
 		OP(OP_EQ)
-			fl->Stack[fl->SP-2] = fl->Stack[fl->SP-2] == fl->Stack[fl->SP-1] ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-2] = FL(Stack)[FL(SP)-2] == FL(Stack)[FL(SP)-1] ? FL(FL_T) : FL(FL_F);
 			POPN(1);
 			NEXT_OP;
 
 		OP(OP_SYMBOLP)
-			fl->Stack[fl->SP-1] = issymbol(fl->Stack[fl->SP-1]) ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = issymbol(FL(Stack)[FL(SP)-1]) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_NOT)
-			fl->Stack[fl->SP-1] = fl->Stack[fl->SP-1] == fl->FL_F ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = FL(Stack)[FL(SP)-1] == FL(FL_F) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_CADR)
-			v = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-1];
 			if(__unlikely(!iscons(v))){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
 			v = cdr_(v);
 			if(__unlikely(!iscons(v))){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			fl->Stack[fl->SP-1] = car_(v);
+			FL(Stack)[FL(SP)-1] = car_(v);
 			NEXT_OP;
 
 		OP(OP_NEG)
 		do_neg:
-			fl->Stack[ipd] = (uintptr_t)ip;
-			fl->Stack[fl->SP-1] = fl_neg(fl->Stack[fl->SP-1]);
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			FL(Stack)[FL(SP)-1] = fl_neg(FL(Stack)[FL(SP)-1]);
 			NEXT_OP;
 
 		OP(OP_NULLP)
-			fl->Stack[fl->SP-1] = fl->Stack[fl->SP-1] == fl->NIL ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = FL(Stack)[FL(SP)-1] == FL(NIL) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_BOOLEANP)
-			v = fl->Stack[fl->SP-1];
-			fl->Stack[fl->SP-1] = (v == fl->FL_T || v == fl->FL_F) ? fl->FL_T : fl->FL_F;
+			v = FL(Stack)[FL(SP)-1];
+			FL(Stack)[FL(SP)-1] = (v == FL(FL_T) || v == FL(FL_F)) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_NUMBERP)
-			v = fl->Stack[fl->SP-1];
-			fl->Stack[fl->SP-1] = fl_isnumber(v) ? fl->FL_T : fl->FL_F;
+			v = FL(Stack)[FL(SP)-1];
+			FL(Stack)[FL(SP)-1] = fl_isnumber(v) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_FIXNUMP)
-			fl->Stack[fl->SP-1] = isfixnum(fl->Stack[fl->SP-1]) ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = isfixnum(FL(Stack)[FL(SP)-1]) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_BOUNDP)
-			fl->Stack[ipd] = (uintptr_t)ip;
-			sym = tosymbol(fl->Stack[fl->SP-1]);
-			fl->Stack[fl->SP-1] = sym->binding == UNBOUND ? fl->FL_F : fl->FL_T;
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			sym = tosymbol(FL(Stack)[FL(SP)-1]);
+			FL(Stack)[FL(SP)-1] = sym->binding == UNBOUND ? FL(FL_F) : FL(FL_T);
 			NEXT_OP;
 
 		OP(OP_BUILTINP)
-			v = fl->Stack[fl->SP-1];
-			fl->Stack[fl->SP-1] = (isbuiltin(v) || iscbuiltin(v)) ? fl->FL_T : fl->FL_F;
+			v = FL(Stack)[FL(SP)-1];
+			FL(Stack)[FL(SP)-1] = (isbuiltin(v) || iscbuiltin(v)) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_FUNCTIONP)
-			v = fl->Stack[fl->SP-1];
-			fl->Stack[fl->SP-1] =
+			v = FL(Stack)[FL(SP)-1];
+			FL(Stack)[FL(SP)-1] =
 				((tag(v) == TAG_FUNCTION &&
 				  (isbuiltin(v) || v>(N_BUILTINS<<3))) ||
-				 iscbuiltin(v)) ? fl->FL_T : fl->FL_F;
+				 iscbuiltin(v)) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_VECTORP)
-			fl->Stack[fl->SP-1] = isvector(fl->Stack[fl->SP-1]) ? fl->FL_T : fl->FL_F;
+			FL(Stack)[FL(SP)-1] = isvector(FL(Stack)[FL(SP)-1]) ? FL(FL_T) : FL(FL_F);
 			NEXT_OP;
 
 		OP(OP_JMPL)
@@ -1301,57 +1301,57 @@
 			NEXT_OP;
 
 		OP(OP_BRFL)
-			ip += POP() == fl->FL_F ? GET_INT32(ip) : 4;
+			ip += POP() == FL(FL_F) ? GET_INT32(ip) : 4;
 			NEXT_OP;
 
 		OP(OP_BRTL)
-			ip += POP() != fl->FL_F ? GET_INT32(ip) : 4;
+			ip += POP() != FL(FL_F) ? GET_INT32(ip) : 4;
 			NEXT_OP;
 
 		OP(OP_BRNEL)
-			ip += fl->Stack[fl->SP-2] != fl->Stack[fl->SP-1] ? GET_INT32(ip) : 4;
+			ip += FL(Stack)[FL(SP)-2] != FL(Stack)[FL(SP)-1] ? GET_INT32(ip) : 4;
 			POPN(2);
 			NEXT_OP;
 
 		OP(OP_BRNNL)
-			ip += POP() != fl->NIL ? GET_INT32(ip) : 4;
+			ip += POP() != FL(NIL) ? GET_INT32(ip) : 4;
 			NEXT_OP;
 
 		OP(OP_BRN)
-			ip += POP() == fl->NIL ? GET_INT16(ip) : 2;
+			ip += POP() == FL(NIL) ? GET_INT16(ip) : 2;
 			NEXT_OP;
 
 		OP(OP_BRNL)
-			ip += POP() == fl->NIL ? GET_INT32(ip) : 4;
+			ip += POP() == FL(NIL) ? GET_INT32(ip) : 4;
 			NEXT_OP;
 
 		OP(OP_EQV)
-			if(fl->Stack[fl->SP-2] == fl->Stack[fl->SP-1])
-				v = fl->FL_T;
-			else if(!leafp(fl->Stack[fl->SP-2]) || !leafp(fl->Stack[fl->SP-1]))
-				v = fl->FL_F;
+			if(FL(Stack)[FL(SP)-2] == FL(Stack)[FL(SP)-1])
+				v = FL(FL_T);
+			else if(!leafp(FL(Stack)[FL(SP)-2]) || !leafp(FL(Stack)[FL(SP)-1]))
+				v = FL(FL_F);
 			else
-				v = compare_(fl->Stack[fl->SP-2], fl->Stack[fl->SP-1], 1) == 0 ? fl->FL_T : fl->FL_F;
-			fl->Stack[fl->SP-2] = v;
+				v = compare_(FL(Stack)[FL(SP)-2], FL(Stack)[FL(SP)-1], 1) == 0 ? FL(FL_T) : FL(FL_F);
+			FL(Stack)[FL(SP)-2] = v;
 			POPN(1);
 			NEXT_OP;
 
 		OP(OP_EQUAL)
-			if(fl->Stack[fl->SP-2] == fl->Stack[fl->SP-1])
-				v = fl->FL_T;
+			if(FL(Stack)[FL(SP)-2] == FL(Stack)[FL(SP)-1])
+				v = FL(FL_T);
 			else
-				v = compare_(fl->Stack[fl->SP-2], fl->Stack[fl->SP-1], 1) == 0 ? fl->FL_T : fl->FL_F;
-			fl->Stack[fl->SP-2] = v;
+				v = compare_(FL(Stack)[FL(SP)-2], FL(Stack)[FL(SP)-1], 1) == 0 ? FL(FL_T) : FL(FL_F);
+			FL(Stack)[FL(SP)-2] = v;
 			POPN(1);
 			NEXT_OP;
 
 		OP(OP_SETCAR)
-			v = fl->Stack[fl->SP-2];
+			v = FL(Stack)[FL(SP)-2];
 			if(__unlikely(!iscons(v))){
-				fl->Stack[ipd] = (uintptr_t)ip;
+				FL(Stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			car_(v) = fl->Stack[fl->SP-1];
+			car_(v) = FL(Stack)[FL(SP)-1];
 			POPN(1);
 			NEXT_OP;
 
@@ -1359,11 +1359,11 @@
 			n = *ip++;
 		apply_list:
 			if(n > 0){
-				v = list(&fl->Stack[fl->SP-n], n, 0);
+				v = list(&FL(Stack)[FL(SP)-n], n, 0);
 				POPN(n);
 				PUSH(v);
 			}else{
-				PUSH(fl->NIL);
+				PUSH(FL(NIL));
 			}
 			NEXT_OP;
 
@@ -1376,14 +1376,14 @@
 			n = *ip++;
 		apply_apply:
 			v = POP();	 // arglist
-			n = fl->SP-(n-2);  // n-2 == # leading arguments not in the list
+			n = FL(SP)-(n-2);  // n-2 == # leading arguments not in the list
 			while(iscons(v)){
-				if(fl->SP >= fl->N_STACK)
+				if(FL(SP) >= FL(N_STACK))
 					grow_stack();
 				PUSH(car_(v));
 				v = cdr_(v);
 			}
-			n = fl->SP-n;
+			n = FL(SP)-n;
 			goto do_call;
 
 		OP(OP_ADD)
@@ -1390,10 +1390,10 @@
 			n = *ip++;
 		apply_add:
 			s = 0;
-			i = fl->SP-n;
-			for(; i < fl->SP; i++){
-				if(isfixnum(fl->Stack[i])){
-					s += numval(fl->Stack[i]);
+			i = FL(SP)-n;
+			for(; i < FL(SP); i++){
+				if(isfixnum(FL(Stack)[i])){
+					s += numval(FL(Stack)[i]);
 					if(__unlikely(!fits_fixnum(s))){
 						i++;
 						goto add_ovf;
@@ -1400,12 +1400,12 @@
 					}
 				}else{
 				add_ovf:
-					fl->Stack[ipd] = (uintptr_t)ip;
-					v = fl_add_any(&fl->Stack[i], fl->SP-i, s);
+					FL(Stack)[ipd] = (uintptr_t)ip;
+					v = fl_add_any(&FL(Stack)[i], FL(SP)-i, s);
 					break;
 				}
 			}
-			if(i == fl->SP)
+			if(i == FL(SP))
 				v = fixnum(s);
 			POPN(n);
 			PUSH(v);
@@ -1418,15 +1418,15 @@
 				goto do_sub2;
 			if(n == 1)
 				goto do_neg;
-			fl->Stack[ipd] = (uintptr_t)ip;
-			i = fl->SP-n;
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			i = FL(SP)-n;
 			// we need to pass the full arglist on to fl_add_any
 			// so it can handle rest args properly
-			PUSH(fl->Stack[i]);
-			fl->Stack[i] = fixnum(0);
-			fl->Stack[i+1] = fl_neg(fl_add_any(&fl->Stack[i], n, 0));
-			fl->Stack[i] = POP();
-			v = fl_add_any(&fl->Stack[i], 2, 0);
+			PUSH(FL(Stack)[i]);
+			FL(Stack)[i] = fixnum(0);
+			FL(Stack)[i+1] = fl_neg(fl_add_any(&FL(Stack)[i], n, 0));
+			FL(Stack)[i] = POP();
+			v = fl_add_any(&FL(Stack)[i], 2, 0);
 			POPN(n);
 			PUSH(v);
 			NEXT_OP;
@@ -1433,23 +1433,23 @@
 
 		OP(OP_SUB2)
 		do_sub2:
-			if(bothfixnums(fl->Stack[fl->SP-2], fl->Stack[fl->SP-1])){
-				s = numval(fl->Stack[fl->SP-2]) - numval(fl->Stack[fl->SP-1]);
+			if(bothfixnums(FL(Stack)[FL(SP)-2], FL(Stack)[FL(SP)-1])){
+				s = numval(FL(Stack)[FL(SP)-2]) - numval(FL(Stack)[FL(SP)-1]);
 				v = fits_fixnum(s) ? fixnum(s) : mk_xlong(s);
 			}else{
-				fl->Stack[ipd] = (uintptr_t)ip;
-				fl->Stack[fl->SP-1] = fl_neg(fl->Stack[fl->SP-1]);
-				v = fl_add_any(&fl->Stack[fl->SP-2], 2, 0);
+				FL(Stack)[ipd] = (uintptr_t)ip;
+				FL(Stack)[FL(SP)-1] = fl_neg(FL(Stack)[FL(SP)-1]);
+				v = fl_add_any(&FL(Stack)[FL(SP)-2], 2, 0);
 			}
 			POPN(1);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_MUL)
 			n = *ip++;
 		apply_mul:
-			fl->Stack[ipd] = (uintptr_t)ip;
-			v = fl_mul_any(&fl->Stack[fl->SP-n], n);
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			v = fl_mul_any(&FL(Stack)[FL(SP)-n], n);
 			POPN(n);
 			PUSH(v);
 			NEXT_OP;
@@ -1457,18 +1457,18 @@
 		OP(OP_DIV)
 			n = *ip++;
 		apply_div:
-			fl->Stack[ipd] = (uintptr_t)ip;
-			i = fl->SP-n;
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			i = FL(SP)-n;
 			if(n == 1){
-				fl->Stack[fl->SP-1] = fl_div2(fixnum(1), fl->Stack[i]);
+				FL(Stack)[FL(SP)-1] = fl_div2(fixnum(1), FL(Stack)[i]);
 			}else{
 				if(n > 2){
-					PUSH(fl->Stack[i]);
-					fl->Stack[i] = fixnum(1);
-					fl->Stack[i+1] = fl_mul_any(&fl->Stack[i], n);
-					fl->Stack[i] = POP();
+					PUSH(FL(Stack)[i]);
+					FL(Stack)[i] = fixnum(1);
+					FL(Stack)[i+1] = fl_mul_any(&FL(Stack)[i], n);
+					FL(Stack)[i] = POP();
 				}
-				v = fl_div2(fl->Stack[i], fl->Stack[i+1]);
+				v = fl_div2(FL(Stack)[i], FL(Stack)[i+1]);
 				POPN(n);
 				PUSH(v);
 			}
@@ -1475,9 +1475,9 @@
 			NEXT_OP;
 
 		OP(OP_IDIV)
-			fl->Stack[ipd] = (uintptr_t)ip;
-			v = fl->Stack[fl->SP-2];
-			e = fl->Stack[fl->SP-1];
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			v = FL(Stack)[FL(SP)-2];
+			e = FL(Stack)[FL(SP)-1];
 			if(bothfixnums(v, e)){
 				if(e == 0)
 					DivideByZeroError();
@@ -1486,23 +1486,23 @@
 				v = fl_idiv2(v, e);
 			}
 			POPN(1);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_NUMEQ)
-			v = fl->Stack[fl->SP-2]; e = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-2]; e = FL(Stack)[FL(SP)-1];
 			if(bothfixnums(v, e))
-				v = v == e ? fl->FL_T : fl->FL_F;
+				v = v == e ? FL(FL_T) : FL(FL_F);
 			else{
-				fl->Stack[ipd] = (uintptr_t)ip;
-				v = numeric_compare(v, e, 1, 0, 1) == 0 ? fl->FL_T : fl->FL_F;
+				FL(Stack)[ipd] = (uintptr_t)ip;
+				v = numeric_compare(v, e, 1, 0, 1) == 0 ? FL(FL_T) : FL(FL_F);
 			}
 			POPN(1);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_COMPARE)
-			fl->Stack[fl->SP-2] = compare_(fl->Stack[fl->SP-2], fl->Stack[fl->SP-1], 0);
+			FL(Stack)[FL(SP)-2] = compare_(FL(Stack)[FL(SP)-2], FL(Stack)[FL(SP)-1], 0);
 			POPN(1);
 			NEXT_OP;
 
@@ -1513,7 +1513,7 @@
 				n = GET_INT32(ip);
 				ip += 4;
 			}
-			fl->Stack[ipd] = (uintptr_t)ip;
+			FL(Stack)[ipd] = (uintptr_t)ip;
 			argcount(nargs, n);
 			NEXT_OP;
 
@@ -1522,7 +1522,7 @@
 		apply_vector:
 			v = alloc_vector(n, 0);
 			if(n){
-				memmove(&vector_elt(v, 0), &fl->Stack[fl->SP-n], n*sizeof(value_t));
+				memmove(&vector_elt(v, 0), &FL(Stack)[FL(SP)-n], n*sizeof(value_t));
 				POPN(n);
 			}
 			PUSH(v);
@@ -1529,41 +1529,41 @@
 			NEXT_OP;
 
 		OP(OP_ASET)
-			e = fl->Stack[fl->SP-3];
-			fl->Stack[ipd] = (uintptr_t)ip;
+			e = FL(Stack)[FL(SP)-3];
+			FL(Stack)[ipd] = (uintptr_t)ip;
 			if(isvector(e)){
-				i = tofixnum(fl->Stack[fl->SP-2]);
+				i = tofixnum(FL(Stack)[FL(SP)-2]);
 				if(__unlikely(i >= vector_size(e)))
-					bounds_error(v, fl->Stack[fl->SP-1]);
-				vector_elt(e, i) = (v = fl->Stack[fl->SP-1]);
+					bounds_error(v, FL(Stack)[FL(SP)-1]);
+				vector_elt(e, i) = (v = FL(Stack)[FL(SP)-1]);
 			}else if(__likely(isarray(e))){
-				v = cvalue_array_aset(&fl->Stack[fl->SP-3]);
+				v = cvalue_array_aset(&FL(Stack)[FL(SP)-3]);
 			}else{
 				type_error("sequence", e);
 			}
 			POPN(2);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_FOR)
-			fl->Stack[ipd] = (uintptr_t)ip;
-			s  = tofixnum(fl->Stack[fl->SP-3]);
-			hi = tofixnum(fl->Stack[fl->SP-2]);
-			v = fl->FL_UNSPECIFIED;
-			fl->SP += 2;
-			n = fl->SP;
+			FL(Stack)[ipd] = (uintptr_t)ip;
+			s  = tofixnum(FL(Stack)[FL(SP)-3]);
+			hi = tofixnum(FL(Stack)[FL(SP)-2]);
+			v = FL(FL_UNSPECIFIED);
+			FL(SP) += 2;
+			n = FL(SP);
 			for(; s <= hi; s++){
-				fl->Stack[fl->SP-2] = fl->Stack[fl->SP-3];
-				fl->Stack[fl->SP-1] = fixnum(s);
+				FL(Stack)[FL(SP)-2] = FL(Stack)[FL(SP)-3];
+				FL(Stack)[FL(SP)-1] = fixnum(s);
 				v = apply_cl(1);
-				fl->SP = n;
+				FL(SP) = n;
 			}
 			POPN(4);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_LOADNIL)
-			PUSH(fl->NIL);
+			PUSH(FL(NIL));
 			NEXT_OP;
 
 		OP(OP_LOADI8)
@@ -1572,7 +1572,7 @@
 			NEXT_OP;
 
 		OP(OP_LOADVL)
-			v = fn_vals(fl->Stack[bp-1]);
+			v = fn_vals(FL(Stack)[bp-1]);
 			v = vector_elt(v, GET_INT32(ip));
 			ip += 4;
 			PUSH(v);
@@ -1579,12 +1579,12 @@
 			NEXT_OP;
 
 		OP(OP_SETGL)
-			v = fn_vals(fl->Stack[bp-1]);
+			v = fn_vals(FL(Stack)[bp-1]);
 			v = vector_elt(v, GET_INT32(ip));
 			ip += 4;
 			if(0){
 		OP(OP_SETG)
-				v = fn_vals(fl->Stack[bp-1]);
+				v = fn_vals(FL(Stack)[bp-1]);
 				assert(*ip < vector_size(v));
 				v = vector_elt(v, *ip);
 				ip++;
@@ -1591,7 +1591,7 @@
 			}
 			assert(issymbol(v));
 			sym = (symbol_t*)ptr(v);
-			v = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-1];
 			if(!isconstant(sym))
 				sym->binding = v;
 			NEXT_OP;
@@ -1600,30 +1600,30 @@
 			assert(nargs > 0);
 			i = GET_INT32(ip);
 			ip += 4;
-			v = captured ? vector_elt(fl->Stack[bp], i) : fl->Stack[bp+i];
+			v = captured ? vector_elt(FL(Stack)[bp], i) : FL(Stack)[bp+i];
 			PUSH(v);
 			NEXT_OP;
 
 		OP(OP_SETAL)
 			assert(nargs > 0);
-			v = fl->Stack[fl->SP-1];
+			v = FL(Stack)[FL(SP)-1];
 			i = GET_INT32(ip);
 			ip += 4;
 			if(captured)
-				vector_elt(fl->Stack[bp], i) = v;
+				vector_elt(FL(Stack)[bp], i) = v;
 			else
-				fl->Stack[bp+i] = v;
+				FL(Stack)[bp+i] = v;
 			NEXT_OP;
 
 		OP(OP_SETC)
 			s = *ip++;
 			i = *ip++;
-			v = fl->Stack[bp+nargs];
+			v = FL(Stack)[bp+nargs];
 			while(s--)
 				v = vector_elt(v, vector_size(v)-1);
 			assert(isvector(v));
 			assert(i < vector_size(v));
-			vector_elt(v, i) = fl->Stack[fl->SP-1];
+			vector_elt(v, i) = FL(Stack)[FL(SP)-1];
 			NEXT_OP;
 
 		OP(OP_LOADCL)
@@ -1631,7 +1631,7 @@
 			ip += 4;
 			i = GET_INT32(ip);
 			ip += 4;
-			v = fl->Stack[bp+nargs];
+			v = FL(Stack)[bp+nargs];
 			while(s--)
 				v = vector_elt(v, vector_size(v)-1);
 			PUSH(vector_elt(v, i));
@@ -1642,11 +1642,11 @@
 			ip += 4;
 			i = GET_INT32(ip);
 			ip += 4;
-			v = fl->Stack[bp+nargs];
+			v = FL(Stack)[bp+nargs];
 			while(s--)
 				v = vector_elt(v, vector_size(v)-1);
 			assert(i < vector_size(v));
-			vector_elt(v, i) = fl->Stack[fl->SP-1];
+			vector_elt(v, i) = FL(Stack)[FL(SP)-1];
 			NEXT_OP;
 
 		OP(OP_VARGC)
@@ -1658,37 +1658,37 @@
 			}
 			s = (fixnum_t)nargs - (fixnum_t)i;
 			if(s > 0){
-				v = list(&fl->Stack[bp+i], s, 0);
-				fl->Stack[bp+i] = v;
+				v = list(&FL(Stack)[bp+i], s, 0);
+				FL(Stack)[bp+i] = v;
 				if(s > 1){
-					fl->Stack[bp+i+1] = fl->Stack[bp+nargs+0];
-					fl->Stack[bp+i+2] = fl->Stack[bp+nargs+1];
-					fl->Stack[bp+i+3] = i+1;
-					//fl->Stack[bp+i+4] = 0;
-					fl->Stack[bp+i+5] = 0;
-					fl->SP =  bp+i+6;
-					fl->curr_frame = fl->SP;
+					FL(Stack)[bp+i+1] = FL(Stack)[bp+nargs+0];
+					FL(Stack)[bp+i+2] = FL(Stack)[bp+nargs+1];
+					FL(Stack)[bp+i+3] = i+1;
+					//FL(Stack)[bp+i+4] = 0;
+					FL(Stack)[bp+i+5] = 0;
+					FL(SP) =  bp+i+6;
+					FL(curr_frame) = FL(SP);
 				}
 			}else if(__unlikely(s < 0)){
-				fl->Stack[ipd] = (uintptr_t)ip;
-				lerrorf(fl->ArgError, "too few arguments");
+				FL(Stack)[ipd] = (uintptr_t)ip;
+				lerrorf(FL(ArgError), "too few arguments");
 			}else{
 				PUSH(0);
-				fl->Stack[fl->SP-3] = i+1;
-				fl->Stack[fl->SP-4] = fl->Stack[fl->SP-5];
-				fl->Stack[fl->SP-5] = fl->Stack[fl->SP-6];
-				fl->Stack[fl->SP-6] = fl->NIL;
-				fl->curr_frame = fl->SP;
+				FL(Stack)[FL(SP)-3] = i+1;
+				FL(Stack)[FL(SP)-4] = FL(Stack)[FL(SP)-5];
+				FL(Stack)[FL(SP)-5] = FL(Stack)[FL(SP)-6];
+				FL(Stack)[FL(SP)-6] = FL(NIL);
+				FL(curr_frame) = FL(SP);
 			}
-			ipd = fl->SP-2;
+			ipd = FL(SP)-2;
 			nargs = i+1;
 			NEXT_OP;
 
 		OP(OP_TRYCATCH)
-			fl->Stack[ipd] = (uintptr_t)ip;
+			FL(Stack)[ipd] = (uintptr_t)ip;
 			v = do_trycatch();
 			POPN(1);
-			fl->Stack[fl->SP-1] = v;
+			FL(Stack)[FL(SP)-1] = v;
 			NEXT_OP;
 
 		OP(OP_OPTARGS)
@@ -1697,28 +1697,28 @@
 			n = GET_INT32(ip);
 			ip += 4;
 			if(__unlikely(nargs < i)){
-				fl->Stack[ipd] = (uintptr_t)ip;
-				lerrorf(fl->ArgError, "too few arguments");
+				FL(Stack)[ipd] = (uintptr_t)ip;
+				lerrorf(FL(ArgError), "too few arguments");
 			}
 			if((int32_t)n > 0){
 				if(__unlikely(nargs > n)){
-					fl->Stack[ipd] = (uintptr_t)ip;
-					lerrorf(fl->ArgError, "too many arguments");
+					FL(Stack)[ipd] = (uintptr_t)ip;
+					lerrorf(FL(ArgError), "too many arguments");
 				}
 			}else
 				n = -n;
 			if(__likely(n > nargs)){
 				n -= nargs;
-				fl->SP += n;
-				fl->Stack[fl->SP-1] = fl->Stack[fl->SP-n-1];
-				fl->Stack[fl->SP-2] = fl->Stack[fl->SP-n-2];
-				fl->Stack[fl->SP-3] = nargs+n;
-				fl->Stack[fl->SP-4] = fl->Stack[fl->SP-n-4];
-				fl->Stack[fl->SP-5] = fl->Stack[fl->SP-n-5];
-				fl->curr_frame = fl->SP;
-				ipd = fl->SP-2;
+				FL(SP) += n;
+				FL(Stack)[FL(SP)-1] = FL(Stack)[FL(SP)-n-1];
+				FL(Stack)[FL(SP)-2] = FL(Stack)[FL(SP)-n-2];
+				FL(Stack)[FL(SP)-3] = nargs+n;
+				FL(Stack)[FL(SP)-4] = FL(Stack)[FL(SP)-n-4];
+				FL(Stack)[FL(SP)-5] = FL(Stack)[FL(SP)-n-5];
+				FL(curr_frame) = FL(SP);
+				ipd = FL(SP)-2;
 				for(i = 0; i < n; i++)
-					fl->Stack[bp+nargs+i] = UNBOUND;
+					FL(Stack)[bp+nargs+i] = UNBOUND;
 				nargs += n;
 			}
 			NEXT_OP;
@@ -1726,12 +1726,12 @@
 		OP(OP_BRBOUND)
 			i = GET_INT32(ip);
 			ip += 4;
-			v = captured ? vector_elt(fl->Stack[bp], i) : fl->Stack[bp+i];
-			PUSH(v != UNBOUND ? fl->FL_T : fl->FL_F);
+			v = captured ? vector_elt(FL(Stack)[bp], i) : FL(Stack)[bp+i];
+			PUSH(v != UNBOUND ? FL(FL_T) : FL(FL_F));
 			NEXT_OP;
 
 		OP(OP_KEYARGS)
-			v = fn_vals(fl->Stack[bp-1]);
+			v = fn_vals(FL(Stack)[bp-1]);
 			v = vector_elt(v, 0);
 			i = GET_INT32(ip);
 			ip += 4;
@@ -1739,7 +1739,7 @@
 			ip += 4;
 			s = GET_INT32(ip);
 			ip += 4;
-			fl->Stack[ipd] = (uintptr_t)ip;
+			FL(Stack)[ipd] = (uintptr_t)ip;
 			nargs = process_keys(v, i, n, labs(s)-(i+n), bp, nargs, s<0);
 			NEXT_OP;
 		}
@@ -1780,32 +1780,32 @@
 static value_t
 _stacktrace(uint32_t top)
 {
-	value_t lst = fl->NIL;
+	value_t lst = FL(NIL);
 
 	fl_gc_handle(&lst);
 	while(top > 0){
-		const uint8_t *ip1 = (void*)fl->Stack[top-2];
-		uint32_t sz = fl->Stack[top-3]+1;
+		const uint8_t *ip1 = (void*)FL(Stack)[top-2];
+		uint32_t sz = FL(Stack)[top-3]+1;
 		uint32_t bp = top-5-sz;
-		value_t func = fl->Stack[bp];
+		value_t func = FL(Stack)[bp];
 		const uint8_t *ip0 = cv_data((cvalue_t*)ptr(fn_bcode(func)));
 		value_t ip = ip1 - ip0 - 1; /* -1: ip1 is *after* the one that was being executed */
 		value_t v = alloc_vector(sz+1, 0);
 		vector_elt(v, 0) = fixnum(ip);
 		vector_elt(v, 1) = func;
-		if(fl->Stack[top-1] /*captured*/){
+		if(FL(Stack)[top-1] /*captured*/){
 			memmove(&vector_elt(v, 2),
-				   &vector_elt(fl->Stack[bp+1], 0), (sz-1)*sizeof(value_t));
+				   &vector_elt(FL(Stack)[bp+1], 0), (sz-1)*sizeof(value_t));
 		}else{
 			for(uint32_t i = 1; i < sz; i++){
-				value_t si = fl->Stack[bp+i];
+				value_t si = FL(Stack)[bp+i];
 				// if there's an error evaluating argument defaults some slots
 				// might be left set to UNBOUND (issue #22)
-				vector_elt(v, i+1) = si == UNBOUND ? fl->FL_UNSPECIFIED : si;
+				vector_elt(v, i+1) = si == UNBOUND ? FL(FL_UNSPECIFIED) : si;
 			}
 		}
 		lst = fl_cons(v, lst);
-		top = fl->Stack[top-4];
+		top = FL(Stack)[top-4];
 	}
 	fl_free_gc_handles(1);
 	return lst;
@@ -1818,7 +1818,7 @@
 	USED(args);
 	argcount(nargs, 0);
 	gc(0);
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 BUILTIN("function", function)
@@ -1854,8 +1854,8 @@
 	value_t fv = tagptr(fn, TAG_FUNCTION);
 	fn->bcode = args[0];
 	fn->vals = args[1];
-	fn->env = fl->NIL;
-	fn->name = fl->LAMBDA;
+	fn->env = FL(NIL);
+	fn->name = FL(LAMBDA);
 	if(nargs > 2){
 		if(issymbol(args[2])){
 			fn->name = args[2];
@@ -1870,7 +1870,7 @@
 			}
 		}
 		if(__unlikely(isgensym(fn->name)))
-			lerrorf(fl->ArgError, "name should not be a gensym");
+			lerrorf(FL(ArgError), "name should not be a gensym");
 	}
 	return fv;
 }
@@ -1919,10 +1919,10 @@
 
 BUILTIN("append", append)
 {
-	value_t first = fl->NIL, lst, lastcons = fl->NIL;
+	value_t first = FL(NIL), lst, lastcons = FL(NIL);
 	int i;
 	if(nargs == 0)
-		return fl->NIL;
+		return FL(NIL);
 	fl_gc_handle(&first);
 	fl_gc_handle(&lastcons);
 	for(i = 0; i < nargs; i++){
@@ -1929,12 +1929,12 @@
 		lst = args[i];
 		if(iscons(lst)){
 			lst = copy_list(lst);
-			if(first == fl->NIL)
+			if(first == FL(NIL))
 				first = lst;
 			else
 				cdr_(lastcons) = lst;
-			lastcons = tagptr((((cons_t*)fl->curheap)-1), TAG_CONS);
-		}else if(lst != fl->NIL){
+			lastcons = tagptr((((cons_t*)FL(curheap))-1), TAG_CONS);
+		}else if(lst != FL(NIL)){
 			type_error("cons", lst);
 		}
 	}
@@ -1955,72 +1955,72 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	return _stacktrace(fl->throwing_frame ? fl->throwing_frame : fl->curr_frame);
+	return _stacktrace(FL(throwing_frame) ? FL(throwing_frame) : FL(curr_frame));
 }
 
 BUILTIN("map", map)
 {
 	if(__unlikely(nargs < 2))
-		lerrorf(fl->ArgError, "too few arguments");
+		lerrorf(FL(ArgError), "too few arguments");
 	if(!iscons(args[1]))
-		return fl->NIL;
+		return FL(NIL);
 	value_t first, last, v;
-	int64_t argSP = args-fl->Stack;
-	assert(argSP >= 0 && argSP < fl->N_STACK);
+	int64_t argSP = args-FL(Stack);
+	assert(argSP >= 0 && argSP < FL(N_STACK));
 	if(nargs == 2){
-		if(fl->SP+3 > fl->N_STACK)
+		if(FL(SP)+3 > FL(N_STACK))
 			grow_stack();
-		PUSH(fl->Stack[argSP]);
-		PUSH(car_(fl->Stack[argSP+1]));
+		PUSH(FL(Stack)[argSP]);
+		PUSH(car_(FL(Stack)[argSP+1]));
 		v = _applyn(1);
 		PUSH(v);
 		v = mk_cons();
-		car_(v) = POP(); cdr_(v) = fl->NIL;
+		car_(v) = POP(); cdr_(v) = FL(NIL);
 		last = first = v;
-		fl->Stack[argSP+1] = cdr_(fl->Stack[argSP+1]);
+		FL(Stack)[argSP+1] = cdr_(FL(Stack)[argSP+1]);
 		fl_gc_handle(&first);
 		fl_gc_handle(&last);
-		while(iscons(fl->Stack[argSP+1])){
-			fl->Stack[fl->SP-2] = fl->Stack[argSP];
-			fl->Stack[fl->SP-1] = car_(fl->Stack[argSP+1]);
+		while(iscons(FL(Stack)[argSP+1])){
+			FL(Stack)[FL(SP)-2] = FL(Stack)[argSP];
+			FL(Stack)[FL(SP)-1] = car_(FL(Stack)[argSP+1]);
 			v = _applyn(1);
 			PUSH(v);
 			v = mk_cons();
-			car_(v) = POP(); cdr_(v) = fl->NIL;
+			car_(v) = POP(); cdr_(v) = FL(NIL);
 			cdr_(last) = v;
 			last = v;
-			fl->Stack[argSP+1] = cdr_(fl->Stack[argSP+1]);
+			FL(Stack)[argSP+1] = cdr_(FL(Stack)[argSP+1]);
 		}
 		POPN(2);
 		fl_free_gc_handles(2);
 	}else{
 		int i;
-		while(fl->SP+nargs+1 > fl->N_STACK)
+		while(FL(SP)+nargs+1 > FL(N_STACK))
 			grow_stack();
-		PUSH(fl->Stack[argSP]);
+		PUSH(FL(Stack)[argSP]);
 		for(i = 1; i < nargs; i++){
-			PUSH(car(fl->Stack[argSP+i]));
-			fl->Stack[argSP+i] = cdr_(fl->Stack[argSP+i]);
+			PUSH(car(FL(Stack)[argSP+i]));
+			FL(Stack)[argSP+i] = cdr_(FL(Stack)[argSP+i]);
 		}
 		v = _applyn(nargs-1);
 		POPN(nargs);
 		PUSH(v);
 		v = mk_cons();
-		car_(v) = POP(); cdr_(v) = fl->NIL;
+		car_(v) = POP(); cdr_(v) = FL(NIL);
 		last = first = v;
 		fl_gc_handle(&first);
 		fl_gc_handle(&last);
-		while(iscons(fl->Stack[argSP+1])){
-			PUSH(fl->Stack[argSP]);
+		while(iscons(FL(Stack)[argSP+1])){
+			PUSH(FL(Stack)[argSP]);
 			for(i = 1; i < nargs; i++){
-				PUSH(car(fl->Stack[argSP+i]));
-				fl->Stack[argSP+i] = cdr_(fl->Stack[argSP+i]);
+				PUSH(car(FL(Stack)[argSP+i]));
+				FL(Stack)[argSP+i] = cdr_(FL(Stack)[argSP+i]);
 			}
 			v = _applyn(nargs-1);
 			POPN(nargs);
 			PUSH(v);
 			v = mk_cons();
-			car_(v) = POP(); cdr_(v) = fl->NIL;
+			car_(v) = POP(); cdr_(v) = FL(NIL);
 			cdr_(last) = v;
 			last = v;
 		}
@@ -2035,7 +2035,7 @@
 		argcount(nargs, 1);
 	double s = nargs > 0 ? todouble(args[0]) : 0;
 	sleep_ms(s * 1000.0);
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 static const builtinspec_t builtin_fns[] = {
@@ -2051,82 +2051,81 @@
 {
 	int i;
 
-	fl = LLT_ALLOC(sizeof(*fl));
-	memset(fl, 0, sizeof(*fl));
-	fl->SCR_WIDTH = 80;
+	memset(&fl, 0, sizeof(fl));
+	FL(SCR_WIDTH) = 80;
 
-	fl->heapsize = initial_heapsize;
+	FL(heapsize) = initial_heapsize;
 
-	fl->fromspace = LLT_ALLOC(fl->heapsize);
-	fl->tospace   = LLT_ALLOC(fl->heapsize);
-	fl->curheap = fl->fromspace;
-	fl->lim = fl->curheap+fl->heapsize-sizeof(cons_t);
-	fl->consflags = bitvector_new(fl->heapsize/sizeof(cons_t), 1);
-	htable_new(&fl->printconses, 32);
+	FL(fromspace) = LLT_ALLOC(FL(heapsize));
+	FL(tospace)   = LLT_ALLOC(FL(heapsize));
+	FL(curheap) = FL(fromspace);
+	FL(lim) = FL(curheap)+FL(heapsize)-sizeof(cons_t);
+	FL(consflags) = bitvector_new(FL(heapsize)/sizeof(cons_t), 1);
+	htable_new(&FL(printconses), 32);
 	comparehash_init();
-	fl->N_STACK = 262144;
-	fl->Stack = LLT_ALLOC(fl->N_STACK*sizeof(value_t));
+	FL(N_STACK) = 262144;
+	FL(Stack) = LLT_ALLOC(FL(N_STACK)*sizeof(value_t));
 
-	fl->FL_NIL = fl->NIL = builtin(OP_THE_EMPTY_LIST);
-	fl->FL_T = builtin(OP_BOOL_CONST_T);
-	fl->FL_F = builtin(OP_BOOL_CONST_F);
-	fl->FL_EOF = builtin(OP_EOF_OBJECT);
-	fl->LAMBDA = symbol("λ");
-	fl->FUNCTION = symbol("function");
-	fl->QUOTE = symbol("quote");
-	fl->TRYCATCH = symbol("trycatch");
-	fl->BACKQUOTE = symbol("quasiquote");
-	fl->COMMA = symbol("unquote");
-	fl->COMMAAT = symbol("unquote-splicing");
-	fl->COMMADOT = symbol("unquote-nsplicing");
-	fl->IOError = symbol("io-error");
-	fl->ParseError = symbol("parse-error");
-	fl->TypeError = symbol("type-error");
-	fl->ArgError = symbol("arg-error");
-	fl->UnboundError = symbol("unbound-error");
-	fl->KeyError = symbol("key-error");
-	fl->MemoryError = symbol("memory-error");
-	fl->BoundsError = symbol("bounds-error");
-	fl->DivideError = symbol("divide-error");
-	fl->EnumerationError = symbol("enumeration-error");
-	fl->Error = symbol("error");
-	fl->pairsym = symbol("pair");
-	fl->symbolsym = symbol("symbol");
-	fl->fixnumsym = symbol("fixnum");
-	fl->vectorsym = symbol("vector");
-	fl->builtinsym = symbol("builtin");
-	fl->booleansym = symbol("boolean");
-	fl->nullsym = symbol("null");
-	fl->definesym = symbol("define");
-	fl->defmacrosym = symbol("define-macro");
-	fl->forsym = symbol("for");
-	fl->setqsym = symbol("set!");
-	fl->evalsym = symbol("eval");
-	fl->vu8sym = symbol("vu8");
-	fl->fnsym = symbol("fn");
-	fl->nulsym = symbol("nul");
-	fl->alarmsym = symbol("alarm");
-	fl->backspacesym = symbol("backspace");
-	fl->tabsym = symbol("tab");
-	fl->linefeedsym = symbol("linefeed");
-	fl->vtabsym = symbol("vtab");
-	fl->pagesym = symbol("page");
-	fl->returnsym = symbol("return");
-	fl->escsym = symbol("esc");
-	fl->spacesym = symbol("space");
-	fl->deletesym = symbol("delete");
-	fl->newlinesym = symbol("newline");
-	fl->tsym = symbol("t");
-	fl->Tsym = symbol("T");
-	fl->fsym = symbol("f");
-	fl->Fsym = symbol("F");
-	fl->builtins_table_sym = symbol("*builtins*");
-	set(fl->printprettysym = symbol("*print-pretty*"), fl->FL_T);
-	set(fl->printreadablysym = symbol("*print-readably*"), fl->FL_T);
-	set(fl->printwidthsym = symbol("*print-width*"), fixnum(fl->SCR_WIDTH));
-	set(fl->printlengthsym = symbol("*print-length*"), fl->FL_F);
-	set(fl->printlevelsym = symbol("*print-level*"), fl->FL_F);
-	fl->lasterror = fl->NIL;
+	FL(FL_NIL) = FL(NIL) = builtin(OP_THE_EMPTY_LIST);
+	FL(FL_T) = builtin(OP_BOOL_CONST_T);
+	FL(FL_F) = builtin(OP_BOOL_CONST_F);
+	FL(FL_EOF) = builtin(OP_EOF_OBJECT);
+	FL(LAMBDA) = symbol("λ");
+	FL(FUNCTION) = symbol("function");
+	FL(QUOTE) = symbol("quote");
+	FL(TRYCATCH) = symbol("trycatch");
+	FL(BACKQUOTE) = symbol("quasiquote");
+	FL(COMMA) = symbol("unquote");
+	FL(COMMAAT) = symbol("unquote-splicing");
+	FL(COMMADOT) = symbol("unquote-nsplicing");
+	FL(IOError) = symbol("io-error");
+	FL(ParseError) = symbol("parse-error");
+	FL(TypeError) = symbol("type-error");
+	FL(ArgError) = symbol("arg-error");
+	FL(UnboundError) = symbol("unbound-error");
+	FL(KeyError) = symbol("key-error");
+	FL(MemoryError) = symbol("memory-error");
+	FL(BoundsError) = symbol("bounds-error");
+	FL(DivideError) = symbol("divide-error");
+	FL(EnumerationError) = symbol("enumeration-error");
+	FL(Error) = symbol("error");
+	FL(pairsym) = symbol("pair");
+	FL(symbolsym) = symbol("symbol");
+	FL(fixnumsym) = symbol("fixnum");
+	FL(vectorsym) = symbol("vector");
+	FL(builtinsym) = symbol("builtin");
+	FL(booleansym) = symbol("boolean");
+	FL(nullsym) = symbol("null");
+	FL(definesym) = symbol("define");
+	FL(defmacrosym) = symbol("define-macro");
+	FL(forsym) = symbol("for");
+	FL(setqsym) = symbol("set!");
+	FL(evalsym) = symbol("eval");
+	FL(vu8sym) = symbol("vu8");
+	FL(fnsym) = symbol("fn");
+	FL(nulsym) = symbol("nul");
+	FL(alarmsym) = symbol("alarm");
+	FL(backspacesym) = symbol("backspace");
+	FL(tabsym) = symbol("tab");
+	FL(linefeedsym) = symbol("linefeed");
+	FL(vtabsym) = symbol("vtab");
+	FL(pagesym) = symbol("page");
+	FL(returnsym) = symbol("return");
+	FL(escsym) = symbol("esc");
+	FL(spacesym) = symbol("space");
+	FL(deletesym) = symbol("delete");
+	FL(newlinesym) = symbol("newline");
+	FL(tsym) = symbol("t");
+	FL(Tsym) = symbol("T");
+	FL(fsym) = symbol("f");
+	FL(Fsym) = symbol("F");
+	FL(builtins_table_sym) = symbol("*builtins*");
+	set(FL(printprettysym) = symbol("*print-pretty*"), FL(FL_T));
+	set(FL(printreadablysym) = symbol("*print-readably*"), FL(FL_T));
+	set(FL(printwidthsym) = symbol("*print-width*"), fixnum(FL(SCR_WIDTH)));
+	set(FL(printlengthsym) = symbol("*print-length*"), FL(FL_F));
+	set(FL(printlevelsym) = symbol("*print-level*"), FL(FL_F));
+	FL(lasterror) = FL(NIL);
 	for(i = 0; i < nelem(builtins); i++){
 		if(builtins[i].name)
 			setc(symbol(builtins[i].name), builtin(i));
@@ -2151,12 +2150,12 @@
 	set(symbol("*os-name*"), symbol("unknown"));
 #endif
 
-	fl->the_empty_vector = tagptr(alloc_words(1), TAG_VECTOR);
-	vector_setsize(fl->the_empty_vector, 0);
+	FL(the_empty_vector) = tagptr(alloc_words(1), TAG_VECTOR);
+	vector_setsize(FL(the_empty_vector), 0);
 
 	cvalues_init();
 
-	fl->memory_exception_value = fl_list2(fl->MemoryError, cvalue_static_cstring("out of memory"));
+	FL(memory_exception_value) = fl_list2(FL(MemoryError), cvalue_static_cstring("out of memory"));
 	const builtinspec_t *b;
 	for(i = 0, b = builtin_fns; i < nelem(builtin_fns); i++, b++)
 		setc(symbol(b->name), cbuiltin(b->name, b->fptr));
@@ -2171,7 +2170,7 @@
 value_t
 fl_toplevel_eval(value_t expr)
 {
-	return fl_applyn(1, symbol_value(fl->evalsym), expr);
+	return fl_applyn(1, symbol_value(FL(evalsym)), expr);
 }
 
 int
@@ -2182,17 +2181,17 @@
 	symbol_t *sym;
 
 	PUSH(sys_image_iostream);
-	saveSP = fl->SP;
+	saveSP = FL(SP);
 	FL_TRY{
 		while(1){
-			e = fl_read_sexpr(fl->Stack[fl->SP-1]);
-			if(ios_eof(value2c(ios_t*, fl->Stack[fl->SP-1])))
+			e = fl_read_sexpr(FL(Stack)[FL(SP)-1]);
+			if(ios_eof(value2c(ios_t*, FL(Stack)[FL(SP)-1])))
 				break;
 			if(isfunction(e)){
 				// stage 0 format: series of thunks
 				PUSH(e);
 				(void)_applyn(0);
-				fl->SP = saveSP;
+				FL(SP) = saveSP;
 			}else{
 				// stage 1 format: list alternating symbol/value
 				while(iscons(e)){
@@ -2208,11 +2207,11 @@
 	}
 	FL_CATCH_NO_INC{
 		ios_puts("fatal error during bootstrap:\n", ios_stderr);
-		fl_print(ios_stderr, fl->lasterror);
+		fl_print(ios_stderr, FL(lasterror));
 		ios_putc('\n', ios_stderr);
 		return 1;
 	}
-	ios_close(value2c(ios_t*, fl->Stack[fl->SP-1]));
+	ios_close(value2c(ios_t*, FL(Stack)[FL(SP)-1]));
 	POPN(1);
 	return 0;
 }
--- a/flisp.h
+++ b/flisp.h
@@ -104,10 +104,10 @@
 
 // allocate n consecutive conses
 #define cons_reserve(n) tagptr(alloc_words((n)*2), TAG_CONS)
-#define cons_index(c)  (((cons_t*)ptr(c))-((cons_t*)fl->fromspace))
-#define ismarked(c)     bitvector_get(fl->consflags, cons_index(c))
-#define mark_cons(c)   bitvector_set(fl->consflags, cons_index(c), 1)
-#define unmark_cons(c) bitvector_set(fl->consflags, cons_index(c), 0)
+#define cons_index(c)  (((cons_t*)ptr(c))-((cons_t*)FL(fromspace)))
+#define ismarked(c)     bitvector_get(FL(consflags), cons_index(c))
+#define mark_cons(c)   bitvector_set(FL(consflags), cons_index(c), 1)
+#define unmark_cons(c) bitvector_set(FL(consflags), cons_index(c), 0)
 
 #define isforwarded(v) (((value_t*)ptr(v))[0] == TAG_FWD)
 #define forwardloc(v) (((value_t*)ptr(v))[1])
@@ -140,11 +140,11 @@
 #define iskeyword(s) ((s)->flags & FLAG_KEYWORD)
 #define symbol_value(s) (((symbol_t*)ptr(s))->binding)
 #define sym_to_numtype(s) (((symbol_t*)ptr(s))->numtype)
-#define ismanaged(v) ((((uint8_t*)ptr(v)) >= fl->fromspace) && (((uint8_t*)ptr(v)) < fl->fromspace+fl->heapsize))
+#define ismanaged(v) ((((uint8_t*)ptr(v)) >= FL(fromspace)) && (((uint8_t*)ptr(v)) < FL(fromspace)+FL(heapsize)))
 #define isgensym(x)  (issymbol(x) && ismanaged(x))
 #define isfunction(x) (tag(x) == TAG_FUNCTION && (x) > (N_BUILTINS<<3))
 #define isclosure(x) isfunction(x)
-#define iscbuiltin(x) (iscvalue(x) && cv_class(ptr(x)) == fl->builtintype)
+#define iscbuiltin(x) (iscvalue(x) && cv_class(ptr(x)) == FL(builtintype))
 // utility for iterating over all arguments in a builtin
 // i=index, i0=start index, arg = var for each arg, args = arg array
 // assumes "nargs" is the argument count
@@ -154,13 +154,13 @@
 
 #define PUSH(v) \
 	do{ \
-		fl->Stack[fl->SP++] = (v); \
+		FL(Stack)[FL(SP)++] = (v); \
 	}while(0)
 #define POPN(n) \
 	do{ \
-		fl->SP -= (n); \
+		FL(SP) -= (n); \
 	}while(0)
-#define POP() (fl->Stack[--fl->SP])
+#define POP() (FL(Stack)[--FL(SP)])
 
 int isbuiltin(value_t x);
 void fl_init(size_t initial_heapsize);
@@ -226,9 +226,9 @@
 
 #define FL_TRY_EXTERN \
 	fl_exception_context_t _ctx; int l__tr, l__ca; \
-	fl_savestate(&_ctx); fl->exctx = &_ctx; \
+	fl_savestate(&_ctx); FL(exctx) = &_ctx; \
 	if(!setjmp(_ctx.buf)) \
-		for(l__tr=1; l__tr; l__tr=0, (void)(fl->exctx = fl->exctx->prev))
+		for(l__tr=1; l__tr; l__tr=0, (void)(FL(exctx) = FL(exctx)->prev))
 
 #define FL_CATCH_EXTERN_NO_RESTORE \
 	else \
@@ -249,7 +249,7 @@
 #define argcount(nargs, c) \
 	do{ \
 		if(__unlikely(nargs != c)) \
-			lerrorf(fl->ArgError, "arity mismatch: wanted %d, got %d", c, nargs); \
+			lerrorf(FL(ArgError), "arity mismatch: wanted %d, got %d", c, nargs); \
 	}while(0)
 
 typedef struct {
@@ -302,7 +302,7 @@
 #define cv_len(cv) (((cvalue_t*)(cv))->len)
 #define cv_type(cv) (cv_class(cv)->type)
 #define cv_data(cv) (((cvalue_t*)(cv))->data)
-#define cv_isstr(cv) (cv_class(cv)->eltype == fl->bytetype)
+#define cv_isstr(cv) (cv_class(cv)->eltype == FL(bytetype))
 #define cv_isPOD(cv) (cv_class(cv)->init != nil)
 #define cvalue_data(v) cv_data((cvalue_t*)ptr(v))
 #define cvalue_len(v) cv_len((cvalue_t*)ptr(v))
@@ -423,4 +423,5 @@
 	int HPOS, VPOS;
 };
 
-extern __thread Fl *fl;
+extern Fl fl;
+#define FL(f) fl.f
--- a/flmain.c
+++ b/flmain.c
@@ -13,7 +13,7 @@
 argv_list(int argc, char *argv[])
 {
 	int i;
-	value_t lst = fl->FL_NIL, temp;
+	value_t lst = FL(FL_NIL), temp;
 	fl_gc_handle(&lst);
 	fl_gc_handle(&temp);
 	for(i = argc-1; i >= 0; i--){
@@ -41,7 +41,7 @@
 
 	fl_init(512*1024);
 
-	value_t f = cvalue(fl->iostreamtype, sizeof(ios_t));
+	value_t f = cvalue(FL(iostreamtype), sizeof(ios_t));
 	ios_t *s = value2c(ios_t*, f);
 	ios_static_buffer(s, boot, bootsz);
 
@@ -54,7 +54,7 @@
 	}
 	FL_CATCH_EXTERN_NO_RESTORE{
 		ios_puts("fatal error:\n", ios_stderr);
-		fl_print(ios_stderr, fl->lasterror);
+		fl_print(ios_stderr, FL(lasterror));
 		ios_putc('\n', ios_stderr);
 		break;
 	}
--- a/iostream.c
+++ b/iostream.c
@@ -39,13 +39,13 @@
 static int
 isiostream(value_t v)
 {
-	return iscvalue(v) && cv_class(ptr(v)) == fl->iostreamtype;
+	return iscvalue(v) && cv_class(ptr(v)) == FL(iostreamtype);
 }
 
 BUILTIN("iostream?", iostreamp)
 {
 	argcount(nargs, 1);
-	return isiostream(args[0]) ? fl->FL_T : fl->FL_F;
+	return isiostream(args[0]) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("eof-object", eof_object)
@@ -52,13 +52,13 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	return fl->FL_EOF;
+	return FL(FL_EOF);
 }
 
 BUILTIN("eof-object?", eof_objectp)
 {
 	argcount(nargs, 1);
-	return args[0] == fl->FL_EOF ? fl->FL_T : fl->FL_F;
+	return args[0] == FL(FL_EOF) ? FL(FL_T) : FL(FL_F);
 }
 
 ios_t *
@@ -75,24 +75,24 @@
 		argcount(nargs, 1);
 	int i, r = 0, w = 0, c = 0, t = 0, a = 0;
 	for(i = 1; i < nargs; i++){
-		if(args[i] == fl->rdsym)
+		if(args[i] == FL(rdsym))
 			r = 1;
-		else if(args[i] == fl->wrsym)
+		else if(args[i] == FL(wrsym))
 			w = 1;
-		else if(args[i] == fl->apsym)
+		else if(args[i] == FL(apsym))
 			a = w = 1;
-		else if(args[i] == fl->crsym)
+		else if(args[i] == FL(crsym))
 			c = w = 1;
-		else if(args[i] == fl->truncsym)
+		else if(args[i] == FL(truncsym))
 			t = w = 1;
 	}
 	if((r|w|c|t|a) == 0)
 		r = 1;  // default to reading
-	value_t f = cvalue(fl->iostreamtype, sizeof(ios_t));
+	value_t f = cvalue(FL(iostreamtype), sizeof(ios_t));
 	char *fname = tostring(args[0]);
 	ios_t *s = value2c(ios_t*, f);
 	if(ios_file(s, fname, r, w, c, t) == nil)
-		lerrorf(fl->IOError, "could not open \"%s\"", fname);
+		lerrorf(FL(IOError), "could not open \"%s\"", fname);
 	if(a)
 		ios_seek_end(s);
 	return f;
@@ -102,10 +102,10 @@
 {
 	argcount(nargs, 0);
 	USED(args);
-	value_t f = cvalue(fl->iostreamtype, sizeof(ios_t));
+	value_t f = cvalue(FL(iostreamtype), sizeof(ios_t));
 	ios_t *s = value2c(ios_t*, f);
 	if(ios_mem(s, 0) == nil)
-		lerrorf(fl->MemoryError, "could not allocate stream");
+		lerrorf(FL(MemoryError), "could not allocate stream");
 	return f;
 }
 
@@ -115,7 +115,7 @@
 	if(nargs > 1)
 		argcount(nargs, 1);
 	else if(nargs == 0)
-		arg = symbol_value(fl->instrsym);
+		arg = symbol_value(FL(instrsym));
 	else
 		arg = args[0];
 	ios_t *s = toiostream(arg);
@@ -123,7 +123,7 @@
 	value_t v = fl_read_sexpr(arg);
 	fl_free_gc_handles(1);
 	if(ios_eof(s))
-		return fl->FL_EOF;
+		return FL(FL_EOF);
 	return v;
 }
 
@@ -134,10 +134,10 @@
 	Rune r;
 	int res;
 	if((res = ios_getutf8(s, &r)) == IOS_EOF)
-		//lerrorf(fl->IOError, "end of file reached");
-		return fl->FL_EOF;
+		//lerrorf(FL(IOError), "end of file reached");
+		return FL(FL_EOF);
 	if(res == 0)
-		lerrorf(fl->IOError, "invalid UTF-8 sequence");
+		lerrorf(FL(IOError), "invalid UTF-8 sequence");
 	return mk_rune(r);
 }
 
@@ -148,10 +148,10 @@
 	ios_t *s = toiostream(args[0]);
 	int r = ios_wait(s, nargs > 1 ? todouble(args[1]) : -1);
 	if(r >= 0)
-		return r ? fl->FL_T : fl->FL_F;
+		return r ? FL(FL_T) : FL(FL_F);
 	if(r == IOS_EOF)
-		return fl->FL_EOF;
-	lerrorf(fl->IOError, "i/o error");
+		return FL(FL_EOF);
+	lerrorf(FL(IOError), "i/o error");
 }
 
 BUILTIN("io-putc", io_putc)
@@ -158,7 +158,7 @@
 {
 	argcount(nargs, 2);
 	ios_t *s = toiostream(args[0]);
-	if(!iscprim(args[1]) || ((cprim_t*)ptr(args[1]))->type != fl->runetype)
+	if(!iscprim(args[1]) || ((cprim_t*)ptr(args[1]))->type != FL(runetype))
 		type_error("rune", args[1]);
 	Rune r = *(Rune*)cp_data((cprim_t*)ptr(args[1]));
 	return fixnum(ios_pututf8(s, r));
@@ -171,7 +171,7 @@
 	off_t off = tooffset(args[1]);
 	off_t res = ios_skip(s, off);
 	if(res < 0)
-		return fl->FL_F;
+		return FL(FL_F);
 	return sizeof(res) == sizeof(int64_t) ? mk_int64(res) : mk_int32(res);
 }
 
@@ -178,7 +178,7 @@
 BUILTIN("io-flush", io_flush)
 {
 	argcount(nargs, 1);
-	return ios_flush(toiostream(args[0])) == 0 ? fl->FL_T : fl->FL_F;
+	return ios_flush(toiostream(args[0])) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("io-close", io_close)
@@ -185,7 +185,7 @@
 {
 	argcount(nargs, 1);
 	ios_close(toiostream(args[0]));
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 BUILTIN("io-discardbuffer", io_discardbuffer)
@@ -192,13 +192,13 @@
 {
 	argcount(nargs, 1);
 	ios_purge(toiostream(args[0]));
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 BUILTIN("io-eof?", io_eofp)
 {
 	argcount(nargs, 1);
-	return ios_eof(toiostream(args[0])) ? fl->FL_T : fl->FL_F;
+	return ios_eof(toiostream(args[0])) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("io-seek", io_seek)
@@ -208,8 +208,8 @@
 	size_t pos = toulong(args[1]);
 	off_t res = ios_seek(s, (off_t)pos);
 	if(res < 0)
-		return fl->FL_F;
-	return fl->FL_T;
+		return FL(FL_F);
+	return FL(FL_T);
 }
 
 BUILTIN("io-pos", io_pos)
@@ -218,7 +218,7 @@
 	ios_t *s = toiostream(args[0]);
 	off_t res = ios_pos(s);
 	if(res < 0)
-		return fl->FL_F;
+		return FL(FL_F);
 	return size_wrap((size_t)res);
 }
 
@@ -227,7 +227,7 @@
 	if(nargs < 1 || nargs > 2)
 		argcount(nargs, 1);
 	ios_t *s;
-	s = nargs == 2 ? toiostream(args[1]) : toiostream(symbol_value(fl->outstrsym));
+	s = nargs == 2 ? toiostream(args[1]) : toiostream(symbol_value(FL(outstrsym)));
 	fl_print(s, args[0]);
 	return args[0];
 }
@@ -246,7 +246,7 @@
 	}else{
 		ft = get_type(args[1]);
 		if(ft->eltype != nil && !iscons(cdr_(cdr_(args[1]))))
-			lerrorf(fl->ArgError, "incomplete type");
+			lerrorf(FL(ArgError), "incomplete type");
 		n = ft->size;
 	}
 	value_t cv = cvalue(ft, n);
@@ -256,8 +256,8 @@
 	else data = cp_data(ptr(cv));
 	size_t got = ios_read(s, data, n);
 	if(got < n)
-		//lerrorf(fl->IOError, "end of input reached");
-		return fl->FL_EOF;
+		//lerrorf(FL(IOError), "end of input reached");
+		return FL(FL_EOF);
 	return cv;
 }
 
@@ -278,9 +278,9 @@
 	if(nargs < 2 || nargs > 4)
 		argcount(nargs, 2);
 	ios_t *s = toiostream(args[0]);
-	if(iscprim(args[1]) && ((cprim_t*)ptr(args[1]))->type == fl->runetype){
+	if(iscprim(args[1]) && ((cprim_t*)ptr(args[1]))->type == FL(runetype)){
 		if(nargs > 2)
-			lerrorf(fl->ArgError, "offset argument not supported for characters");
+			lerrorf(FL(ArgError), "offset argument not supported for characters");
 		Rune r = *(Rune*)cp_data(ptr(args[1]));
 		return fixnum(ios_pututf8(s, r));
 	}
@@ -299,7 +299,7 @@
 {
 	if(nargs < 1 || nargs > 3)
 		argcount(nargs, 1);
-	ios_t *s = toiostream(symbol_value(fl->outstrsym));
+	ios_t *s = toiostream(symbol_value(FL(outstrsym)));
 	uint8_t *data;
 	size_t sz, offs = 0;
 	to_sized_ptr(args[0], &data, &sz);
@@ -309,7 +309,7 @@
 		data += offs;
 	}
 	hexdump(s, data, nb, offs);
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 static char
@@ -318,8 +318,8 @@
 	size_t uldelim = toulong(arg);
 	if(uldelim > 0x7f){
 		// runes > 0x7f, or anything else > 0xff, are out of range
-		if((iscprim(arg) && cp_class(ptr(arg)) == fl->runetype) || uldelim > 0xff)
-			lerrorf(fl->ArgError, "delimiter out of range");
+		if((iscprim(arg) && cp_class(ptr(arg)) == FL(runetype)) || uldelim > 0xff)
+			lerrorf(FL(ArgError), "delimiter out of range");
 	}
 	return (char)uldelim;
 }
@@ -346,7 +346,7 @@
 		((uint8_t*)cv->data)[n] = 0;
 	}
 	if(n == 0 && ios_eof(src))
-		return fl->FL_EOF;
+		return FL(FL_EOF);
 	return str;
 }
 
@@ -384,7 +384,7 @@
 	}else{
 		uint8_t *b = ios_takebuf(st, &n); n--;
 		b[n] = '\0';
-		str = cvalue_from_ref(fl->stringtype, b, n, fl->FL_NIL);
+		str = cvalue_from_ref(FL(stringtype), b, n, FL(FL_NIL));
 		cv_autorelease(ptr(str));
 	}
 	return str;
@@ -395,7 +395,7 @@
 	argcount(nargs, 1);
 	ios_t *src = toiostream(args[0]);
 	if(src->bm != bm_mem)
-		lerrorf(fl->ArgError, "requires memory stream");
+		lerrorf(FL(ArgError), "requires memory stream");
 	return stream_to_string(&args[0]);
 }
 
@@ -402,16 +402,16 @@
 void
 iostream_init(void)
 {
-	fl->iostreamsym = symbol("iostream");
-	fl->rdsym = symbol(":read");
-	fl->wrsym = symbol(":write");
-	fl->apsym = symbol(":append");
-	fl->crsym = symbol(":create");
-	fl->truncsym = symbol(":truncate");
-	fl->instrsym = symbol("*input-stream*");
-	fl->outstrsym = symbol("*output-stream*");
-	fl->iostreamtype = define_opaque_type(fl->iostreamsym, sizeof(ios_t), &iostream_vtable, nil);
-	setc(symbol("*stdout*"), cvalue_from_ref(fl->iostreamtype, ios_stdout, sizeof(ios_t), fl->FL_NIL));
-	setc(symbol("*stderr*"), cvalue_from_ref(fl->iostreamtype, ios_stderr, sizeof(ios_t), fl->FL_NIL));
-	setc(symbol("*stdin*" ), cvalue_from_ref(fl->iostreamtype, ios_stdin, sizeof(ios_t), fl->FL_NIL));
+	FL(iostreamsym) = symbol("iostream");
+	FL(rdsym) = symbol(":read");
+	FL(wrsym) = symbol(":write");
+	FL(apsym) = symbol(":append");
+	FL(crsym) = symbol(":create");
+	FL(truncsym) = symbol(":truncate");
+	FL(instrsym) = symbol("*input-stream*");
+	FL(outstrsym) = symbol("*output-stream*");
+	FL(iostreamtype) = define_opaque_type(FL(iostreamsym), sizeof(ios_t), &iostream_vtable, nil);
+	setc(symbol("*stdout*"), cvalue_from_ref(FL(iostreamtype), ios_stdout, sizeof(ios_t), FL(FL_NIL)));
+	setc(symbol("*stderr*"), cvalue_from_ref(FL(iostreamtype), ios_stderr, sizeof(ios_t), FL(FL_NIL)));
+	setc(symbol("*stdin*" ), cvalue_from_ref(FL(iostreamtype), ios_stdin, sizeof(ios_t), FL(FL_NIL)));
 }
--- a/print.c
+++ b/print.c
@@ -12,9 +12,9 @@
 {
 	ios_putc(c, f);
 	if(c == '\n')
-		fl->HPOS = 0;
+		FL(HPOS) = 0;
 	else
-		fl->HPOS++;
+		FL(HPOS)++;
 }
 
 static void
@@ -21,7 +21,7 @@
 outs(char *s, ios_t *f)
 {
 	ios_puts(s, f);
-	fl->HPOS += u8_strwidth(s);
+	FL(HPOS) += u8_strwidth(s);
 }
 
 static void
@@ -28,7 +28,7 @@
 outsn(char *s, ios_t *f, size_t n)
 {
 	ios_write(f, s, n);
-	fl->HPOS += u8_strwidth(s);
+	FL(HPOS) += u8_strwidth(s);
 }
 
 static int
@@ -35,12 +35,12 @@
 outindent(int n, ios_t *f)
 {
 	// move back to left margin if we get too indented
-	if(n > fl->SCR_WIDTH-12)
+	if(n > FL(SCR_WIDTH)-12)
 		n = 2;
 	int n0 = n;
 	ios_putc('\n', f);
-	fl->VPOS++;
-	fl->HPOS = n;
+	FL(VPOS)++;
+	FL(HPOS) = n;
 	while(n >= 8){
 		ios_putc('\t', f);
 		n -= 8;
@@ -70,9 +70,9 @@
 	value_t *bp;
 	while(iscons(v)){
 		if(ismarked(v)){
-			bp = (value_t*)ptrhash_bp(&fl->printconses, (void*)v);
+			bp = (value_t*)ptrhash_bp(&FL(printconses), (void*)v);
 			if(*bp == (value_t)HT_NOTFOUND)
-				*bp = fixnum(fl->printlabel++);
+				*bp = fixnum(FL(printlabel)++);
 			return;
 		}
 		mark_cons(v);
@@ -82,9 +82,9 @@
 	if(!ismanaged(v) || issymbol(v))
 		return;
 	if(ismarked(v)){
-		bp = (value_t*)ptrhash_bp(&fl->printconses, (void*)v);
+		bp = (value_t*)ptrhash_bp(&FL(printconses), (void*)v);
 		if(*bp == (value_t)HT_NOTFOUND)
-			*bp = fixnum(fl->printlabel++);
+			*bp = fixnum(FL(printlabel)++);
 		return;
 	}
 	if(isvector(v)){
@@ -173,8 +173,8 @@
 		return (cv_len((cvalue_t*)ptr(v)) < SMALL_STR_LEN);
 	return (
 		isfixnum(v) || isbuiltin(v) || iscprim(v) ||
-		v == fl->FL_F || v == fl->FL_T ||
-		v == fl->FL_NIL || v == fl->FL_EOF
+		v == FL(FL_F) || v == FL(FL_T) ||
+		v == FL(FL_NIL) || v == FL(FL_EOF)
 	);
 }
 
@@ -187,7 +187,7 @@
 		return 1;
 	if(iscons(v)){
 		if(tinyp(car_(v)) &&
-		   (tinyp(cdr_(v)) || (iscons(cdr_(v)) && tinyp(car_(cdr_(v))) && cdr_(cdr_(v)) == fl->NIL)))
+		   (tinyp(cdr_(v)) || (iscons(cdr_(v)) && tinyp(car_(cdr_(v))) && cdr_(cdr_(v)) == FL(NIL))))
 			return 1;
 		return 0;
 	}
@@ -205,8 +205,8 @@
 specialindent(value_t head)
 {
 	// indent these forms 2 spaces, not lined up with the first argument
-	if(head == fl->LAMBDA || head == fl->TRYCATCH || head == fl->definesym ||
-		head == fl->defmacrosym || head == fl->forsym)
+	if(head == FL(LAMBDA) || head == FL(TRYCATCH) || head == FL(definesym) ||
+		head == FL(defmacrosym) || head == FL(forsym))
 		return 2;
 	return -1;
 }
@@ -217,7 +217,7 @@
 	// get the width of an expression if we can do so cheaply
 	if(issymbol(v))
 		return u8_strwidth(symbol_name(v));
-	if(iscprim(v) && ptr(v) != nil && cp_class((cprim_t*)ptr(v)) == fl->runetype)
+	if(iscprim(v) && ptr(v) != nil && cp_class((cprim_t*)ptr(v)) == FL(runetype))
 		return 4;
 	return -1;
 }
@@ -241,7 +241,7 @@
 indentafter3(value_t head, value_t v)
 {
 	// for certain X always indent (X a b c) after b
-	return ((head == fl->forsym) && !allsmallp(cdr_(v)));
+	return ((head == FL(forsym)) && !allsmallp(cdr_(v)));
 }
 
 static int
@@ -248,7 +248,7 @@
 indentafter2(value_t head, value_t v)
 {
 	// for certain X always indent (X a b) after a
-	return ((head == fl->definesym || head == fl->defmacrosym) &&
+	return ((head == FL(definesym) || head == FL(defmacrosym)) &&
 			!allsmallp(cdr_(v)));
 }
 
@@ -258,9 +258,9 @@
 	// indent before every subform of a special form, unless every
 	// subform is "small"
 	value_t c = car_(v);
-	if(c == fl->LAMBDA || c == fl->setqsym)
+	if(c == FL(LAMBDA) || c == FL(setqsym))
 		return 0;
-	if(c == fl->IF) // TODO: others
+	if(c == FL(IF)) // TODO: others
 		return !allsmallp(cdr_(v));
 	return 0;
 }
@@ -280,13 +280,13 @@
 {
 	value_t cd;
 	char *op;
-	if(iscons(cdr_(v)) && cdr_(cdr_(v)) == fl->NIL &&
-		!ptrhash_has(&fl->printconses, (void*)cdr_(v)) &&
-		(((car_(v) == fl->QUOTE)	 && (op = "'"))  ||
-		 ((car_(v) == fl->BACKQUOTE) && (op = "`"))  ||
-		 ((car_(v) == fl->COMMA)	 && (op = ","))  ||
-		 ((car_(v) == fl->COMMAAT)   && (op = ",@")) ||
-		 ((car_(v) == fl->COMMADOT)  && (op = ",.")))){
+	if(iscons(cdr_(v)) && cdr_(cdr_(v)) == FL(NIL) &&
+		!ptrhash_has(&FL(printconses), (void*)cdr_(v)) &&
+		(((car_(v) == FL(QUOTE))	 && (op = "'"))  ||
+		 ((car_(v) == FL(BACKQUOTE)) && (op = "`"))  ||
+		 ((car_(v) == FL(COMMA))	 && (op = ","))  ||
+		 ((car_(v) == FL(COMMAAT))   && (op = ",@")) ||
+		 ((car_(v) == FL(COMMADOT))  && (op = ",.")))){
 		// special prefix syntax
 		unmark_cons(v);
 		unmark_cons(cdr_(v));
@@ -294,9 +294,9 @@
 		fl_print_child(f, car_(cdr_(v)));
 		return;
 	}
-	int startpos = fl->HPOS;
+	int startpos = FL(HPOS);
 	outc('(', f);
-	int newindent = fl->HPOS, blk = blockindent(v);
+	int newindent = FL(HPOS), blk = blockindent(v);
 	int lastv, n = 0, si, ind, est, always = 0, nextsmall, thistiny;
 	if(!blk)
 		always = indentevery(v);
@@ -306,15 +306,15 @@
 	int n_unindented = 1;
 	while(1){
 		cd = cdr_(v);
-		if(fl->print_length >= 0 && n >= fl->print_length && cd != fl->NIL){
+		if(FL(print_length) >= 0 && n >= FL(print_length) && cd != FL(NIL)){
 			outsn("...)", f, 4);
 			break;
 		}
-		lastv = fl->VPOS;
+		lastv = FL(VPOS);
 		unmark_cons(v);
 		fl_print_child(f, car_(v));
-		if(!iscons(cd) || ptrhash_has(&fl->printconses, (void*)cd)){
-			if(cd != fl->NIL){
+		if(!iscons(cd) || ptrhash_has(&FL(printconses), (void*)cd)){
+			if(cd != FL(NIL)){
 				outsn(" . ", f, 3);
 				fl_print_child(f, cd);
 			}
@@ -322,8 +322,8 @@
 			break;
 		}
 
-		if(!fl->print_pretty ||
-			((head == fl->LAMBDA) && n == 0)){
+		if(!FL(print_pretty) ||
+			((head == FL(LAMBDA)) && n == 0)){
 			// never break line before lambda-list
 			ind = 0;
 		}else{
@@ -330,14 +330,14 @@
 			est = lengthestimate(car_(cd));
 			nextsmall = smallp(car_(cd));
 			thistiny = tinyp(car_(v));
-			ind = (((fl->VPOS > lastv) ||
-					(fl->HPOS>fl->SCR_WIDTH/2 && !nextsmall && !thistiny && n>0)) ||
+			ind = (((FL(VPOS) > lastv) ||
+					(FL(HPOS)>FL(SCR_WIDTH)/2 && !nextsmall && !thistiny && n>0)) ||
 
-				   (fl->HPOS > fl->SCR_WIDTH-4) ||
+				   (FL(HPOS) > FL(SCR_WIDTH)-4) ||
 
-				   (est != -1 && (fl->HPOS+est > fl->SCR_WIDTH-2)) ||
+				   (est != -1 && (FL(HPOS)+est > FL(SCR_WIDTH)-2)) ||
 
-				   ((head == fl->LAMBDA) && !nextsmall) ||
+				   ((head == FL(LAMBDA)) && !nextsmall) ||
 
 				   (n > 0 && always) ||
 
@@ -361,7 +361,7 @@
 				if(si != -1)
 					newindent = startpos + si;
 				else if(!blk)
-					newindent = fl->HPOS;
+					newindent = FL(HPOS);
 			}
 		}
 		n++;
@@ -375,12 +375,12 @@
 print_circle_prefix(ios_t *f, value_t v)
 {
 	value_t label;
-	if((label = (value_t)ptrhash_get(&fl->printconses, (void*)v)) != (value_t)HT_NOTFOUND){
+	if((label = (value_t)ptrhash_get(&FL(printconses), (void*)v)) != (value_t)HT_NOTFOUND){
 		if(!ismarked(v)){
-			fl->HPOS += ios_printf(f, "#%"PRIdPTR"#", numval(label));
+			FL(HPOS) += ios_printf(f, "#%"PRIdPTR"#", numval(label));
 			return 1;
 		}
-		fl->HPOS += ios_printf(f, "#%"PRIdPTR"=", numval(label));
+		FL(HPOS) += ios_printf(f, "#%"PRIdPTR"=", numval(label));
 	}
 	if(ismanaged(v))
 		unmark_cons(v);
@@ -391,19 +391,19 @@
 fl_print_child(ios_t *f, value_t v)
 {
 	char *name;
-	if(fl->print_level >= 0 && fl->P_LEVEL >= fl->print_level && (iscons(v) || isvector(v) || isclosure(v))){
+	if(FL(print_level) >= 0 && FL(P_LEVEL) >= FL(print_level) && (iscons(v) || isvector(v) || isclosure(v))){
 		outc('#', f);
 		return;
 	}
-	fl->P_LEVEL++;
+	FL(P_LEVEL)++;
 
 	switch(tag(v)){
 	case TAG_NUM: case TAG_NUM1:
-		fl->HPOS += ios_printf(f, "%"PRId64, (int64_t)numval(v));
+		FL(HPOS) += ios_printf(f, "%"PRId64, (int64_t)numval(v));
 		break;
 	case TAG_SYM:
 		name = symbol_name(v);
-		if(fl->print_princ)
+		if(FL(print_princ))
 			outs(name, f);
 		else if(ismanaged(v)){
 			outsn("#:", f, 2);
@@ -412,21 +412,21 @@
 			print_symbol_name(f, name);
 		break;
 	case TAG_FUNCTION:
-		if(v == fl->FL_T)
+		if(v == FL(FL_T))
 			outsn("#t", f, 2);
-		else if(v == fl->FL_F)
+		else if(v == FL(FL_F))
 			outsn("#f", f, 2);
-		else if(v == fl->FL_NIL)
+		else if(v == FL(FL_NIL))
 			outsn("()", f, 2);
-		else if(v == fl->FL_EOF)
+		else if(v == FL(FL_EOF))
 			outsn("#<eof>", f, 6);
 		else if(isbuiltin(v)){
-			if(!fl->print_princ)
+			if(!FL(print_princ))
 				outsn("#.", f, 2);
 			outs(builtins[uintval(v)].name, f);
 		}else{
 			assert(isclosure(v));
-			if(!fl->print_princ){
+			if(!FL(print_princ)){
 				if(print_circle_prefix(f, v))
 					break;
 				function_t *fn = ptr(v);
@@ -440,11 +440,11 @@
 					data[i] -= 48;
 				outc(' ', f);
 				fl_print_child(f, fn->vals);
-				if(fn->env != fl->NIL){
+				if(fn->env != FL(NIL)){
 					outc(' ', f);
 					fl_print_child(f, fn->env);
 				}
-				if(fn->name != fl->LAMBDA){
+				if(fn->name != FL(LAMBDA)){
 					outc(' ', f);
 					fl_print_child(f, fn->name);
 				}
@@ -463,26 +463,26 @@
 	case TAG_CVALUE:
 	case TAG_VECTOR:
 	case TAG_CONS:
-		if(!fl->print_princ && print_circle_prefix(f, v))
+		if(!FL(print_princ) && print_circle_prefix(f, v))
 			break;
 		if(isvector(v)){
 			outs("#(", f);
-			int newindent = fl->HPOS, est;
+			int newindent = FL(HPOS), est;
 			int i, sz = vector_size(v);
 			for(i = 0; i < sz; i++){
-				if(fl->print_length >= 0 && i >= fl->print_length && i < sz-1){
+				if(FL(print_length) >= 0 && i >= FL(print_length) && i < sz-1){
 					outsn("...", f, 3);
 					break;
 				}
 				fl_print_child(f, vector_elt(v, i));
 				if(i < sz-1){
-					if(!fl->print_pretty)
+					if(!FL(print_pretty))
 						outc(' ', f);
 					else{
 						est = lengthestimate(vector_elt(v, i+1));
-						if(fl->HPOS > fl->SCR_WIDTH-4 ||
-						   (est != -1 && (fl->HPOS+est > fl->SCR_WIDTH-2)) ||
-						   (fl->HPOS > fl->SCR_WIDTH/2 && !smallp(vector_elt(v, i+1)) && !tinyp(vector_elt(v, i))))
+						if(FL(HPOS) > FL(SCR_WIDTH)-4 ||
+						   (est != -1 && (FL(HPOS)+est > FL(SCR_WIDTH)-2)) ||
+						   (FL(HPOS) > FL(SCR_WIDTH)/2 && !smallp(vector_elt(v, i+1)) && !tinyp(vector_elt(v, i))))
 							newindent = outindent(newindent, f);
 						else
 							outc(' ', f);
@@ -498,7 +498,7 @@
 			print_pair(f, v);
 		break;
 	}
-	fl->P_LEVEL--;
+	FL(P_LEVEL)--;
 }
 
 static void
@@ -622,20 +622,20 @@
 static void
 cvalue_printdata(ios_t *f, void *data, size_t len, value_t type, int weak)
 {
-	if(type == fl->bytesym){
+	if(type == FL(bytesym)){
 		uint8_t ch = *(uint8_t*)data;
-		if(fl->print_princ)
+		if(FL(print_princ))
 			outc(ch, f);
 		else if(weak)
-			fl->HPOS += ios_printf(f, "0x%hhx", ch);
+			FL(HPOS) += ios_printf(f, "0x%hhx", ch);
 		else
-			fl->HPOS += ios_printf(f, "#byte(0x%hhx)", ch);
-	}else if(type == fl->runesym){
+			FL(HPOS) += ios_printf(f, "#byte(0x%hhx)", ch);
+	}else if(type == FL(runesym)){
 		Rune r = *(Rune*)data;
 		char seq[UTFmax+1];
 		int nb = runetochar(seq, &r);
 		seq[nb] = '\0';
-		if(fl->print_princ){
+		if(FL(print_princ)){
 			outsn(seq, f, nb);
 		}else{
 			outsn("#\\", f, 2);
@@ -655,15 +655,15 @@
 				if(u8_iswprint(r))
 					outs(seq, f);
 				else
-					fl->HPOS += ios_printf(f, "x%04x", r);
+					FL(HPOS) += ios_printf(f, "x%04x", r);
 				break;
 			}
 		}
-	}else if(type == fl->floatsym || type == fl->doublesym){
+	}else if(type == FL(floatsym) || type == FL(doublesym)){
 		char buf[64];
 		double d;
 		int ndec;
-		if(type == fl->floatsym){
+		if(type == FL(floatsym)){
 			d = (double)*(float*)data;
 			ndec = 8;
 		}else{
@@ -676,8 +676,8 @@
 				rep = signbit(d) ? "-nan.0" : "+nan.0";
 			else
 				rep = signbit(d) ? "-inf.0" : "+inf.0";
-			if(type == fl->floatsym && !fl->print_princ && !weak)
-				fl->HPOS += ios_printf(f, "#%s(%s)", symbol_name(type), rep);
+			if(type == FL(floatsym) && !FL(print_princ) && !weak)
+				FL(HPOS) += ios_printf(f, "#%s(%s)", symbol_name(type), rep);
 			else
 				outs(rep, f);
 		}else if(d == 0){
@@ -685,7 +685,7 @@
 				outsn("-0.0", f, 4);
 			else
 				outsn("0.0", f, 3);
-			if(type == fl->floatsym && !fl->print_princ && !weak)
+			if(type == FL(floatsym) && !FL(print_princ) && !weak)
 				outc('f', f);
 		}else{
 			snprint_real(buf, sizeof(buf), d, 0, ndec, 3, 10);
@@ -693,26 +693,26 @@
 			outs(buf, f);
 			if(!hasdec)
 				outsn(".0", f, 2);
-			if(type == fl->floatsym && !fl->print_princ && !weak)
+			if(type == FL(floatsym) && !FL(print_princ) && !weak)
 				outc('f', f);
 		}
 #if defined(ULONG64)
-	}else if(type == fl->uint64sym || type == fl->ulongsym){
+	}else if(type == FL(uint64sym) || type == FL(ulongsym)){
 #else
-	}else if(type == fl->uint64sym){
+	}else if(type == FL(uint64sym)){
 #endif
 		uint64_t ui64 = *(uint64_t*)data;
-		if(weak || fl->print_princ)
-			fl->HPOS += ios_printf(f, "%"PRIu64, ui64);
+		if(weak || FL(print_princ))
+			FL(HPOS) += ios_printf(f, "%"PRIu64, ui64);
 		else
-			fl->HPOS += ios_printf(f, "#%s(%"PRIu64")", symbol_name(type), ui64);
-	}else if(type == fl->bignumsym){
+			FL(HPOS) += ios_printf(f, "#%s(%"PRIu64")", symbol_name(type), ui64);
+	}else if(type == FL(bignumsym)){
 		mpint *i = *(mpint**)data;
 		char *s = mptoa(i, 10, nil, 0);
-		if(weak || fl->print_princ)
-			fl->HPOS += ios_printf(f, "%s", s);
+		if(weak || FL(print_princ))
+			FL(HPOS) += ios_printf(f, "%s", s);
 		else
-			fl->HPOS += ios_printf(f, "#%s(%s)", symbol_name(type), s);
+			FL(HPOS) += ios_printf(f, "#%s(%s)", symbol_name(type), s);
 		LLT_FREE(s);
 	}else if(issymbol(type)){
 		// handle other integer prims. we know it's smaller than uint64
@@ -720,15 +720,15 @@
 		numerictype_t nt = sym_to_numtype(type);
 		if(valid_numtype(nt)){
 			int64_t i64 = conv_to_int64(data, nt);
-			if(weak || fl->print_princ)
-				fl->HPOS += ios_printf(f, "%"PRId64, i64);
+			if(weak || FL(print_princ))
+				FL(HPOS) += ios_printf(f, "%"PRId64, i64);
 			else
-				fl->HPOS += ios_printf(f, "#%s(%"PRId64")", symbol_name(type), i64);
+				FL(HPOS) += ios_printf(f, "#%s(%"PRId64")", symbol_name(type), i64);
 		}else{
-			fl->HPOS += ios_printf(f, "#<%s>", symbol_name(type));
+			FL(HPOS) += ios_printf(f, "#<%s>", symbol_name(type));
 		}
 	}else if(iscons(type)){
-		if(car_(type) == fl->arraysym){
+		if(car_(type) == FL(arraysym)){
 			size_t i;
 			value_t eltype = car(cdr_(type));
 			size_t cnt, elsize;
@@ -741,15 +741,15 @@
 				elsize = ctype_sizeof(eltype, &junk);
 				cnt = elsize ? len/elsize : 0;
 			}
-			if(eltype == fl->bytesym){
-				if(fl->print_princ){
+			if(eltype == FL(bytesym)){
+				if(FL(print_princ)){
 					ios_write(f, data, len);
 					/*
 					char *nl = llt_memrchr(data, '\n', len);
 					if(nl)
-						fl->HPOS = u8_strwidth(nl+1);
+						FL(HPOS) = u8_strwidth(nl+1);
 					else
-						fl->HPOS += u8_strwidth(data);
+						FL(HPOS) += u8_strwidth(data);
 					*/
 				}else{
 					outc('"', f);
@@ -757,23 +757,23 @@
 					outc('"', f);
 				}
 				return;
-			}else if(eltype == fl->runesym){
+			}else if(eltype == FL(runesym)){
 				char buf[UTFmax];
-				if(!fl->print_princ)
+				if(!FL(print_princ))
 					outc('"', f);
 				for(i = 0; i < cnt; i++, data = (char*)data + elsize){
 					int n = runetochar(buf, (Rune*)data);
-					if(fl->print_princ)
+					if(FL(print_princ))
 						ios_write(f, buf, n);
 					else
 						print_string(f, buf, n);
 				}
-				if(!fl->print_princ)
+				if(!FL(print_princ))
 					outc('"', f);
 				return;
 			}
 			if(!weak){
-				if(eltype == fl->uint8sym){
+				if(eltype == FL(uint8sym)){
 					outsn("#vu8(", f, 5);
 				}else{
 					outsn("#array(", f, 7);
@@ -791,7 +791,7 @@
 				data = (char*)data + elsize;
 			}
 			outc(')', f);
-		}else if(car_(type) == fl->enumsym){
+		}else if(car_(type) == FL(enumsym)){
 			int n = *(int*)data;
 			value_t syms = car(cdr_(type));
 			assert(isvector(syms));
@@ -801,7 +801,7 @@
 				outc(' ', f);
 			}
 			if(n >= (int)vector_size(syms)){
-				cvalue_printdata(f, data, len, fl->int32sym, 1);
+				cvalue_printdata(f, data, len, FL(int32sym), 1);
 			}else{
 				fl_print_child(f, vector_elt(syms, n));
 			}
@@ -818,13 +818,13 @@
 	void *data = cptr(v);
 	value_t label;
 
-	if(cv_class(cv) == fl->builtintype){
+	if(cv_class(cv) == FL(builtintype)){
 		void *fptr = *(void**)data;
-		label = (value_t)ptrhash_get(&fl->reverse_dlsym_lookup_table, cv);
+		label = (value_t)ptrhash_get(&FL(reverse_dlsym_lookup_table), cv);
 		if(label == (value_t)HT_NOTFOUND){
-			fl->HPOS += ios_printf(f, "#<builtin @%p>", fptr);
+			FL(HPOS) += ios_printf(f, "#<builtin @%p>", fptr);
 		}else{
-			if(fl->print_princ){
+			if(FL(print_princ)){
 				outs(symbol_name(label), f);
 			}else{
 				outsn("#fn(", f, 4);
@@ -844,36 +844,36 @@
 static void
 set_print_width(void)
 {
-	value_t pw = symbol_value(fl->printwidthsym);
+	value_t pw = symbol_value(FL(printwidthsym));
 	if(!isfixnum(pw))
 		return;
-	fl->SCR_WIDTH = numval(pw);
+	FL(SCR_WIDTH) = numval(pw);
 }
 
 void
 fl_print(ios_t *f, value_t v)
 {
-	fl->print_pretty = symbol_value(fl->printprettysym) != fl->FL_F;
-	if(fl->print_pretty)
+	FL(print_pretty) = symbol_value(FL(printprettysym)) != FL(FL_F);
+	if(FL(print_pretty))
 		set_print_width();
-	fl->print_princ = symbol_value(fl->printreadablysym) == fl->FL_F;
-	value_t pl = symbol_value(fl->printlengthsym);
-	fl->print_length = isfixnum(pl) ? numval(pl) : -1;
-	pl = symbol_value(fl->printlevelsym);
-	fl->print_level = isfixnum(pl) ? numval(pl) : -1;
-	fl->P_LEVEL = 0;
+	FL(print_princ) = symbol_value(FL(printreadablysym)) == FL(FL_F);
+	value_t pl = symbol_value(FL(printlengthsym));
+	FL(print_length) = isfixnum(pl) ? numval(pl) : -1;
+	pl = symbol_value(FL(printlevelsym));
+	FL(print_level) = isfixnum(pl) ? numval(pl) : -1;
+	FL(P_LEVEL) = 0;
 
-	fl->printlabel = 0;
-	if(!fl->print_princ)
+	FL(printlabel) = 0;
+	if(!FL(print_princ))
 		print_traverse(v);
-	fl->HPOS = fl->VPOS = 0;
+	FL(HPOS) = FL(VPOS) = 0;
 
 	fl_print_child(f, v);
 
-	if(fl->print_level >= 0 || fl->print_length >= 0)
-		memset(fl->consflags, 0, 4*bitvector_nwords(fl->heapsize/sizeof(cons_t)));
+	if(FL(print_level) >= 0 || FL(print_length) >= 0)
+		memset(FL(consflags), 0, 4*bitvector_nwords(FL(heapsize)/sizeof(cons_t)));
 
 	if((iscons(v) || isvector(v) || isfunction(v) || iscvalue(v)) &&
-		!fl_isstring(v) && v != fl->FL_T && v != fl->FL_F && v != fl->FL_NIL)
-		htable_reset(&fl->printconses, 32);
+		!fl_isstring(v) && v != FL(FL_T) && v != FL(FL_F) && v != FL(FL_NIL))
+		htable_reset(&FL(printconses), 32);
 }
--- a/read.c
+++ b/read.c
@@ -85,7 +85,7 @@
 	return x;
 }
 
-#define F value2c(ios_t*, fl->readstate->source)
+#define F value2c(ios_t*, FL(readstate)->source)
 
 int
 isnumtok_base(char *tok, value_t *pval, int base)
@@ -203,7 +203,7 @@
 {
 	buf[(*pi)++] = c;
 	if(*pi >= (int)(sizeof(buf)-1))
-		lerrorf(fl->ParseError, "token too long");
+		lerrorf(FL(ParseError), "token too long");
 }
 
 // return: 1 if escaped (forced to be symbol)
@@ -286,7 +286,7 @@
 	else if(c == '#'){
 		ch = ios_getc(F); c = (char)ch;
 		if(ch == IOS_EOF)
-			lerrorf(fl->ParseError, "invalid read macro");
+			lerrorf(FL(ParseError), "invalid read macro");
 		if(c == '.')
 			toktype = TOK_SHARPDOT;
 		else if(c == '\'')
@@ -294,12 +294,12 @@
 		else if(c == '\\'){
 			Rune cval;
 			if(ios_getutf8(F, &cval) == IOS_EOF)
-				lerrorf(fl->ParseError, "end of input in character constant");
+				lerrorf(FL(ParseError), "end of input in character constant");
 			if(cval == 'u' || cval == 'U' || cval == 'x'){
 				read_token('u', 0);
 				if(buf[1] != '\0'){ // not a solitary 'u','U','x'
 					if(!read_numtok(&buf[1], &tokval, 16))
-						lerrorf(fl->ParseError, "invalid hex character constant");
+						lerrorf(FL(ParseError), "invalid hex character constant");
 					cval = numval(tokval);
 				}
 			}else if(cval >= 'a' && cval <= 'z'){
@@ -306,20 +306,20 @@
 				read_token((char)cval, 0);
 				tokval = symbol(buf);
 				if(buf[1] == '\0') USED(cval); /* one character */
-				else if(tokval == fl->nulsym)       cval = 0x00;
-				else if(tokval == fl->alarmsym)     cval = 0x07;
-				else if(tokval == fl->backspacesym) cval = 0x08;
-				else if(tokval == fl->tabsym)       cval = 0x09;
-				else if(tokval == fl->linefeedsym)  cval = 0x0A;
-				else if(tokval == fl->newlinesym)   cval = 0x0A;
-				else if(tokval == fl->vtabsym)      cval = 0x0B;
-				else if(tokval == fl->pagesym)      cval = 0x0C;
-				else if(tokval == fl->returnsym)    cval = 0x0D;
-				else if(tokval == fl->escsym)       cval = 0x1B;
-				else if(tokval == fl->spacesym)     cval = 0x20;
-				else if(tokval == fl->deletesym)    cval = 0x7F;
+				else if(tokval == FL(nulsym))       cval = 0x00;
+				else if(tokval == FL(alarmsym))     cval = 0x07;
+				else if(tokval == FL(backspacesym)) cval = 0x08;
+				else if(tokval == FL(tabsym))       cval = 0x09;
+				else if(tokval == FL(linefeedsym))  cval = 0x0A;
+				else if(tokval == FL(newlinesym))   cval = 0x0A;
+				else if(tokval == FL(vtabsym))      cval = 0x0B;
+				else if(tokval == FL(pagesym))      cval = 0x0C;
+				else if(tokval == FL(returnsym))    cval = 0x0D;
+				else if(tokval == FL(escsym))       cval = 0x1B;
+				else if(tokval == FL(spacesym))     cval = 0x20;
+				else if(tokval == FL(deletesym))    cval = 0x7F;
 				else
-					lerrorf(fl->ParseError, "unknown character #\\%s", buf);
+					lerrorf(FL(ParseError), "unknown character #\\%s", buf);
 			}
 			toktype = TOK_NUM;
 			tokval = mk_rune(cval);
@@ -326,7 +326,7 @@
 		}else if(c == '('){
 			toktype = TOK_SHARPOPEN;
 		}else if(c == '<'){
-			lerrorf(fl->ParseError, "unreadable object");
+			lerrorf(FL(ParseError), "unreadable object");
 		}else if(isdigit(c)){
 			read_token(c, 1);
 			c = (char)ios_getc(F);
@@ -335,10 +335,10 @@
 			else if(c == '=')
 				toktype = TOK_LABEL;
 			else
-				lerrorf(fl->ParseError, "invalid label");
+				lerrorf(FL(ParseError), "invalid label");
 			x = strtoll(buf, &end, 10);
 			if(*end != '\0')
-				lerrorf(fl->ParseError, "invalid label");
+				lerrorf(FL(ParseError), "invalid label");
 			tokval = fixnum(x);
 		}else if(c == '!'){
 			// #! single line comment for shbang script support
@@ -353,7 +353,7 @@
 				ch = ios_getc(F);
 			hashpipe_gotc:
 				if(ch == IOS_EOF)
-					lerrorf(fl->ParseError, "eof within comment");
+					lerrorf(FL(ParseError), "eof within comment");
 				if((char)ch == '|'){
 					ch = ios_getc(F);
 					if((char)ch == '#'){
@@ -386,7 +386,7 @@
 			read_token((char)ch, 0);
 			x = strtol(buf, &end, 10);
 			if(*end != '\0' || buf[0] == '\0')
-				lerrorf(fl->ParseError, "invalid gensym label");
+				lerrorf(FL(ParseError), "invalid gensym label");
 			toktype = TOK_GENSYM;
 			tokval = fixnum(x);
 		}else if(symchar(c)){
@@ -397,7 +397,7 @@
 			    (c == 'd' && (base = 10)) ||
 			    (c == 'x' && (base = 16))) && (isdigit_base(buf[1], base) || buf[1] == '-')){
 				if(!read_numtok(&buf[1], &tokval, base))
-					lerrorf(fl->ParseError, "invalid base %d constant", base);
+					lerrorf(FL(ParseError), "invalid base %d constant", base);
 				return (toktype = TOK_NUM);
 			}
 
@@ -404,7 +404,7 @@
 			toktype = TOK_SHARPSYM;
 			tokval = symbol(buf);
 		}else{
-			lerrorf(fl->ParseError, "unknown read macro");
+			lerrorf(FL(ParseError), "unknown read macro");
 		}
 	}else if(c == ','){
 		toktype = TOK_COMMA;
@@ -441,11 +441,11 @@
 	PUSH(v);
 	assert(s+d > s);
 	value_t newv = alloc_vector(s+d, 1);
-	v = fl->Stack[fl->SP-1];
+	v = FL(Stack)[FL(SP)-1];
 	for(i = 0; i < s; i++)
 		vector_elt(newv, i) = vector_elt(v, i);
 	// use gc to rewrite references from the old vector to the new
-	fl->Stack[fl->SP-1] = newv;
+	FL(Stack)[FL(SP)-1] = newv;
 	if(s > 0){
 		((size_t*)ptr(v))[0] |= 0x1;
 		vector_elt(v, 0) = newv;
@@ -457,21 +457,21 @@
 static value_t
 read_vector(value_t label, uint32_t closer)
 {
-	value_t v = fl->the_empty_vector, elt;
+	value_t v = FL(the_empty_vector), elt;
 	uint32_t i = 0;
 	PUSH(v);
 	if(label != UNBOUND)
-		ptrhash_put(&fl->readstate->backrefs, (void*)label, (void*)v);
+		ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
 	while(peek() != closer){
 		if(ios_eof(F))
-			lerrorf(fl->ParseError, "unexpected end of input");
+			lerrorf(FL(ParseError), "unexpected end of input");
 		if(i >= vector_size(v)){
-			v = fl->Stack[fl->SP-1] = vector_grow(v);
+			v = FL(Stack)[FL(SP)-1] = vector_grow(v);
 			if(label != UNBOUND)
-				ptrhash_put(&fl->readstate->backrefs, (void*)label, (void*)v);
+				ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
 		}
 		elt = do_read_sexpr(UNBOUND);
-		v = fl->Stack[fl->SP-1];
+		v = FL(Stack)[FL(SP)-1];
 		assert(i < vector_size(v));
 		vector_elt(v, i) = elt;
 		i++;
@@ -499,7 +499,7 @@
 			temp = LLT_REALLOC(buf, sz);
 			if(temp == nil){
 				LLT_FREE(buf);
-				lerrorf(fl->ParseError, "out of memory reading string");
+				lerrorf(FL(ParseError), "out of memory reading string");
 			}
 			buf = temp;
 		}
@@ -506,7 +506,7 @@
 		c = ios_getc(F);
 		if(c == IOS_EOF){
 			LLT_FREE(buf);
-			lerrorf(fl->ParseError, "unexpected end of input in string");
+			lerrorf(FL(ParseError), "unexpected end of input in string");
 		}
 		if(c == '"')
 			break;
@@ -514,7 +514,7 @@
 			c = ios_getc(F);
 			if(c == IOS_EOF){
 				LLT_FREE(buf);
-				lerrorf(fl->ParseError, "end of input in escape sequence");
+				lerrorf(FL(ParseError), "end of input in escape sequence");
 			}
 			j = 0;
 			if(octal_digit(c)){
@@ -542,7 +542,7 @@
 					r = strtol(eseq, nil, 16);
 				if(!j || r > Runemax){
 					LLT_FREE(buf);
-					lerrorf(fl->ParseError, "invalid escape sequence");
+					lerrorf(FL(ParseError), "invalid escape sequence");
 				}
 				if(ndig == 2)
 					buf[i++] = (char)r;
@@ -554,7 +554,7 @@
 				char esc = read_escape_control_char((char)c);
 				if(esc == (char)c && !strchr("\\'\"`", esc)){
 					LLT_FREE(buf);
-					lerrorf(fl->ParseError, "invalid escape sequence: \\%c", (char)c);
+					lerrorf(FL(ParseError), "invalid escape sequence: \\%c", (char)c);
 				}
 				buf[i++] = esc;
 			}
@@ -577,19 +577,19 @@
 	value_t c, *pc;
 	uint32_t t;
 
-	PUSH(fl->NIL);
-	pc = &fl->Stack[fl->SP-1];  // to keep track of current cons cell
+	PUSH(FL(NIL));
+	pc = &FL(Stack)[FL(SP)-1];  // to keep track of current cons cell
 	t = peek();
 	while(t != closer){
 		if(ios_eof(F))
-			lerrorf(fl->ParseError, "unexpected end of input");
-		c = mk_cons(); car_(c) = cdr_(c) = fl->NIL;
+			lerrorf(FL(ParseError), "unexpected end of input");
+		c = mk_cons(); car_(c) = cdr_(c) = FL(NIL);
 		if(iscons(*pc))
 			cdr_(*pc) = c;
 		else{
 			*pval = c;
 			if(label != UNBOUND)
-				ptrhash_put(&fl->readstate->backrefs, (void*)label, (void*)c);
+				ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)c);
 		}
 		*pc = c;
 		c = do_read_sexpr(UNBOUND); // must be on separate lines due to
@@ -602,11 +602,11 @@
 			cdr_(*pc) = c;
 			t = peek();
 			if(ios_eof(F))
-				lerrorf(fl->ParseError, "unexpected end of input");
+				lerrorf(FL(ParseError), "unexpected end of input");
 			if(t != closer){
 				take();
 				lerrorf(
-					fl->ParseError,
+					FL(ParseError),
 					"expected '%c'",
 					closer == TOK_CLOSEB ? ']' : (closer == TOK_CLOSEC ? '}' : ')')
 				);
@@ -631,71 +631,71 @@
 	take();
 	switch(t){
 	case TOK_CLOSE:
-		lerrorf(fl->ParseError, "unexpected ')'");
+		lerrorf(FL(ParseError), "unexpected ')'");
 	case TOK_CLOSEB:
-		lerrorf(fl->ParseError, "unexpected ']'");
+		lerrorf(FL(ParseError), "unexpected ']'");
 	case TOK_CLOSEC:
-		lerrorf(fl->ParseError, "unexpected '}'");
+		lerrorf(FL(ParseError), "unexpected '}'");
 	case TOK_DOT:
-		lerrorf(fl->ParseError, "unexpected '.'");
+		lerrorf(FL(ParseError), "unexpected '.'");
 	case TOK_SYM:
 	case TOK_NUM:
 		return tokval;
 	case TOK_COMMA:
-		head = &fl->COMMA; goto listwith;
+		head = &FL(COMMA); goto listwith;
 	case TOK_COMMAAT:
-		head = &fl->COMMAAT; goto listwith;
+		head = &FL(COMMAAT); goto listwith;
 	case TOK_COMMADOT:
-		head = &fl->COMMADOT; goto listwith;
+		head = &FL(COMMADOT); goto listwith;
 	case TOK_BQ:
-		head = &fl->BACKQUOTE; goto listwith;
+		head = &FL(BACKQUOTE); goto listwith;
 	case TOK_QUOTE:
-		head = &fl->QUOTE;
+		head = &FL(QUOTE);
 	listwith:
 		v = cons_reserve(2);
 		car_(v) = *head;
 		cdr_(v) = tagptr(((cons_t*)ptr(v))+1, TAG_CONS);
-		car_(cdr_(v)) = cdr_(cdr_(v)) = fl->NIL;
+		car_(cdr_(v)) = cdr_(cdr_(v)) = FL(NIL);
 		PUSH(v);
 		if(label != UNBOUND)
-			ptrhash_put(&fl->readstate->backrefs, (void*)label, (void*)v);
+			ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
 		v = do_read_sexpr(UNBOUND);
-		car_(cdr_(fl->Stack[fl->SP-1])) = v;
+		car_(cdr_(FL(Stack)[FL(SP)-1])) = v;
 		return POP();
 	case TOK_SHARPQUOTE:
 		// femtoLisp doesn't need symbol-function, so #' does nothing
 		return do_read_sexpr(label);
 	case TOK_OPEN:
-		PUSH(fl->NIL);
-		read_list(&fl->Stack[fl->SP-1], label, TOK_CLOSE);
+		PUSH(FL(NIL));
+		read_list(&FL(Stack)[FL(SP)-1], label, TOK_CLOSE);
 		return POP();
 	case TOK_OPENB:
-		PUSH(fl->NIL);
-		read_list(&fl->Stack[fl->SP-1], label, TOK_CLOSEB);
+		PUSH(FL(NIL));
+		read_list(&FL(Stack)[FL(SP)-1], label, TOK_CLOSEB);
 		return POP();
 	case TOK_OPENC:
-		PUSH(fl->NIL);
-		read_list(&fl->Stack[fl->SP-1], label, TOK_CLOSEC);
+		PUSH(FL(NIL));
+		read_list(&FL(Stack)[FL(SP)-1], label, TOK_CLOSEC);
 		return POP();
 	case TOK_SHARPSYM:
 		sym = tokval;
-		if(sym == fl->tsym || sym == fl->Tsym)
-			return fl->FL_T;
-		if(sym == fl->fsym || sym == fl->Fsym)
-			return fl->FL_F;
+		if(sym == FL(tsym) || sym == FL(Tsym))
+			return FL(FL_T);
+		if(sym == FL(fsym) || sym == FL(Fsym))
+			return FL(FL_F);
 		// constructor notation
 		c = nextchar();
 		if(c != '('){
 			take();
-			lerrorf(fl->ParseError, "expected argument list for %s", symbol_name(tokval));
+			lerrorf(FL(ParseError), "expected argument list for %s", symbol_name(tokval));
 		}
-		PUSH(fl->NIL);
-		read_list(&fl->Stack[fl->SP-1], UNBOUND, TOK_CLOSE);
-		if(sym == fl->vu8sym){
-			sym = fl->arraysym;
-			fl->Stack[fl->SP-1] = fl_cons(fl->uint8sym, fl->Stack[fl->SP-1]);
-		}else if(sym == fl->fnsym){
-			sym = fl->FUNCTION;
+		PUSH(FL(NIL));
+		read_list(&FL(Stack)[FL(SP)-1], UNBOUND, TOK_CLOSE);
+		if(sym == FL(vu8sym)){
+			sym = FL(arraysym);
+			FL(Stack)[FL(SP)-1] = fl_cons(FL(uint8sym), FL(Stack)[FL(SP)-1]);
+		}else if(sym == FL(fnsym)){
+			sym = FL(FUNCTION);
 		}
 		v = symbol_value(sym);
 		if(v == UNBOUND)
@@ -719,20 +719,20 @@
 		return fl_toplevel_eval(sym);
 	case TOK_LABEL:
 		// create backreference label
-		if(ptrhash_has(&fl->readstate->backrefs, (void*)tokval))
-			lerrorf(fl->ParseError, "label %"PRIdPTR" redefined", numval(tokval));
+		if(ptrhash_has(&FL(readstate)->backrefs, (void*)tokval))
+			lerrorf(FL(ParseError), "label %"PRIdPTR" redefined", numval(tokval));
 		oldtokval = tokval;
 		v = do_read_sexpr(tokval);
-		ptrhash_put(&fl->readstate->backrefs, (void*)oldtokval, (void*)v);
+		ptrhash_put(&FL(readstate)->backrefs, (void*)oldtokval, (void*)v);
 		return v;
 	case TOK_BACKREF:
 		// look up backreference
-		v = (value_t)ptrhash_get(&fl->readstate->backrefs, (void*)tokval);
+		v = (value_t)ptrhash_get(&FL(readstate)->backrefs, (void*)tokval);
 		if(v == (value_t)HT_NOTFOUND)
-			lerrorf(fl->ParseError, "undefined label %"PRIdPTR, numval(tokval));
+			lerrorf(FL(ParseError), "undefined label %"PRIdPTR, numval(tokval));
 		return v;
 	case TOK_GENSYM:
-		pv = (value_t*)ptrhash_bp(&fl->readstate->gensyms, (void*)tokval);
+		pv = (value_t*)ptrhash_bp(&FL(readstate)->gensyms, (void*)tokval);
 		if(*pv == (value_t)HT_NOTFOUND)
 			*pv = gensym();
 		return *pv;
@@ -739,7 +739,7 @@
 	case TOK_DOUBLEQUOTE:
 		return read_string();
 	}
-	return fl->FL_UNSPECIFIED;
+	return FL(FL_UNSPECIFIED);
 }
 
 value_t
@@ -747,11 +747,11 @@
 {
 	value_t v;
 	fl_readstate_t state;
-	state.prev = fl->readstate;
+	state.prev = FL(readstate);
 	htable_new(&state.backrefs, 8);
 	htable_new(&state.gensyms, 8);
 	state.source = f;
-	fl->readstate = &state;
+	FL(readstate) = &state;
 	assert(toktype == TOK_NONE);
 	fl_gc_handle(&tokval);
 
@@ -758,7 +758,7 @@
 	v = do_read_sexpr(UNBOUND);
 
 	fl_free_gc_handles(1);
-	fl->readstate = state.prev;
+	FL(readstate) = state.prev;
 	free_readstate(&state);
 	return v;
 }
--- a/sixel.c
+++ b/sixel.c
@@ -26,13 +26,13 @@
 static int
 issixeloutput(value_t v)
 {
-	return iscvalue(v) && cv_class(ptr(v)) == fl->fsotype;
+	return iscvalue(v) && cv_class(ptr(v)) == FL(fsotype);
 }
 
 BUILTIN("sixel-ouput?", fsixel_outputp)
 {
 	argcount(nargs, 1);
-	return issixeloutput(args[0]) ? fl->FL_T : fl->FL_F;
+	return issixeloutput(args[0]) ? FL(FL_T) : FL(FL_F);
 }
 
 static int
@@ -51,17 +51,17 @@
 		numcolors = toulong(args[0]);
 	}
 	if(numcolors < 1 || numcolors > 256)
-		lerrorf(fl->ArgError, "invalid number of colors: %d", numcolors);
-	value_t v = cvalue(fl->fsotype, sizeof(fso_t));
+		lerrorf(FL(ArgError), "invalid number of colors: %d", numcolors);
+	value_t v = cvalue(FL(fsotype), sizeof(fso_t));
 	fso_t *f = value2c(fso_t*, v);
 	if(salloc == nil)
 		sixel_allocator_new(&salloc, malloc, calloc, realloc, free);
 	SIXELSTATUS r = sixel_output_new(&f->out, fso_write, f, salloc);
 	if(SIXEL_FAILED(r))
-		lerrorf(fl->IOError, "could not create sixel output");
+		lerrorf(FL(IOError), "could not create sixel output");
 	r = sixel_dither_new(&f->dither, numcolors, salloc);
 	if(SIXEL_FAILED(r))
-		lerrorf(fl->IOError, "could not create sixel dither");
+		lerrorf(FL(IOError), "could not create sixel dither");
 	sixel_output_set_palette_type(f->out, SIXEL_PALETTETYPE_RGB);
 	sixel_dither_set_pixelformat(f->dither, SIXEL_PIXELFORMAT_PAL8);
 	sixel_dither_set_transparent(f->dither, 0xff);
@@ -84,10 +84,10 @@
 	if(nargs > 2)
 		scaley = toulong(args[2]);
 	if(scalex < 1 || scalex > 32 || scaley < 1 || scaley > 32)
-		lerrorf(fl->ArgError, "invalid scale factor: %dx%d", scalex, scaley);
+		lerrorf(FL(ArgError), "invalid scale factor: %dx%d", scalex, scaley);
 	f->scalex = scalex;
 	f->scaley = scaley;
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 // :: sixel-output -> palette -> [paltype ->] ...
@@ -110,7 +110,7 @@
 		else if(len == 3 && strncmp(s, "hls", 3) == 0)
 			isrgb = false;
 		else
-			lerrorf(fl->ArgError, "invalid palette type (must be either \"rgb\" or \"hls\")");
+			lerrorf(FL(ArgError), "invalid palette type (must be either \"rgb\" or \"hls\")");
 	}
 
 	if(!isarray(args[1]))
@@ -117,7 +117,7 @@
 		type_error("array", args[1]);
 	len = cvalue_arraylen(args[1]);
 	if(f->numcolors*3 != (int)len)
-		lerrorf(fl->ArgError, "invalid palette: expected %d colors, got %d", f->numcolors, (int)len);
+		lerrorf(FL(ArgError), "invalid palette: expected %d colors, got %d", f->numcolors, (int)len);
 
 	fltype_t *type = cv_class(ptr(args[1]));
 	size_t elsize = type->elsz;
@@ -126,10 +126,10 @@
 
 	uint8_t out[256*3] = {0};
 	if(isrgb){
-		if(eltype->type == fl->uint8sym || eltype->type == fl->bytesym)
+		if(eltype->type == FL(uint8sym) || eltype->type == FL(bytesym))
 			memcpy(out, cptr(args[1]), f->numcolors*3);
 		else
-			lerrorf(fl->ArgError, "invalid palette type: expected bytes");
+			lerrorf(FL(ArgError), "invalid palette type: expected bytes");
 	}else{
 		uint8_t *pal = cptr(args[1]);
 		for(int i = 0; i < f->numcolors; i++){
@@ -161,7 +161,7 @@
 	}
 	sixel_dither_set_palette(f->dither, out);
 
-	return fl->FL_T;
+	return FL(FL_T);
 }
 
 // :: sixel-output -> iostream -> pixels -> width -> height -> ...
@@ -185,7 +185,7 @@
 	if(f->scalex > 1 || f->scaley > 1){
 		int ow = w * f->scalex, oh = h * f->scaley, osz = ow*oh;
 		if(ow < 1 || oh < 1 || osz < ow || osz < oh)
-			lerrorf(fl->ArgError, "scaling out of range");
+			lerrorf(FL(ArgError), "scaling out of range");
 		if(f->bufsz < osz){
 			f->buf = LLT_REALLOC(f->buf, osz);
 			f->bufsz = osz;
@@ -200,7 +200,7 @@
 			salloc
 		);
 		if(SIXEL_FAILED(r))
-			lerrorf(fl->IOError, "could not scale image");
+			lerrorf(FL(IOError), "could not scale image");
 		w = ow;
 		h = oh;
 		pix = f->buf;
@@ -211,8 +211,8 @@
 	}
 	r = sixel_encode(pix, w, h, 0, f->dither, f->out);
 	if(SIXEL_FAILED(r))
-		lerrorf(fl->IOError, "could not encode image");
-	return fl->FL_T;
+		lerrorf(FL(IOError), "could not encode image");
+	return FL(FL_T);
 }
 
 static void
@@ -230,7 +230,7 @@
 	sixel_output_destroy(oldf->out);
 	SIXELSTATUS r = sixel_output_new(&f->out, fso_write, f, salloc);
 	if(SIXEL_FAILED(r))
-		lerrorf(fl->IOError, "could not recreate sixel output");
+		lerrorf(FL(IOError), "could not recreate sixel output");
 	sixel_output_set_palette_type(f->out, SIXEL_PALETTETYPE_RGB);
 }
 
@@ -253,6 +253,6 @@
 void
 fsixel_init(void)
 {
-	fl->fsosym = symbol("sixel-output");
-	fl->fsotype = define_opaque_type(fl->fsosym, sizeof(fso_t), &fso_vtable, nil);
+	FL(fsosym) = symbol("sixel-output");
+	FL(fsotype) = define_opaque_type(FL(fsosym), sizeof(fso_t), &fso_vtable, nil);
 }
--- a/string.c
+++ b/string.c
@@ -13,7 +13,7 @@
 BUILTIN("string?", stringp)
 {
 	argcount(nargs, 1);
-	return fl_isstring(args[0]) ? fl->FL_T : fl->FL_F;
+	return fl_isstring(args[0]) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("string-length", string_length)
@@ -46,9 +46,9 @@
 	argcount(nargs, 1);
 	if(iscprim(args[0])){
 		cprim_t *cp = ptr(args[0]);
-		if(cp_class(cp) == fl->runetype){
+		if(cp_class(cp) == FL(runetype)){
 			int w = wcwidth(*(Rune*)cp_data(cp));
-			return w < 0 ? fl->FL_F : fixnum(w);
+			return w < 0 ? FL(FL_F) : fixnum(w);
 		}
 	}
 	return size_wrap(u8_strwidth(tostring(args[0])));
@@ -71,7 +71,7 @@
 	if(iscvalue(args[0])){
 		cvalue_t *cv = ptr(args[0]);
 		fltype_t *t = cv_class(cv);
-		if(t->eltype == fl->runetype){
+		if(t->eltype == FL(runetype)){
 			size_t nr = cv_len(cv) / sizeof(Rune);
 			Rune *r = (Rune*)cv_data(cv);
 			size_t nb = runenlen(r, nr);
@@ -89,7 +89,7 @@
 {
 	int term = 0;
 	if(nargs == 2)
-		term = args[1] != fl->FL_F;
+		term = args[1] != FL(FL_F);
 	else
 		argcount(nargs, 1);
 	if(!fl_isstring(args[0]))
@@ -101,7 +101,7 @@
 	size_t newsz = nc*sizeof(Rune);
 	if(term)
 		newsz += sizeof(Rune);
-	value_t runestr = cvalue(fl->runestringtype, newsz);
+	value_t runestr = cvalue(FL(runestringtype), newsz);
 	ptr = cv_data(ptr(args[0]));  // relocatable pointer
 	Rune *r = cvalue_data(runestr);
 	for(size_t i = 0; i < nb; i++)
@@ -121,16 +121,16 @@
 	fl_gc_handle(&buf);
 	ios_t *s = value2c(ios_t*, buf);
 	int i;
-	value_t oldpr = symbol_value(fl->printreadablysym);
-	value_t oldpp = symbol_value(fl->printprettysym);
-	set(fl->printreadablysym, fl->FL_F);
-	set(fl->printprettysym, fl->FL_F);
+	value_t oldpr = symbol_value(FL(printreadablysym));
+	value_t oldpp = symbol_value(FL(printprettysym));
+	set(FL(printreadablysym), FL(FL_F));
+	set(FL(printprettysym), FL(FL_F));
 	FOR_ARGS(i, 0, arg, args){
 		USED(arg);
 		fl_print(s, args[i]);
 	}
-	set(fl->printreadablysym, oldpr);
-	set(fl->printprettysym, oldpp);
+	set(FL(printreadablysym), oldpr);
+	set(FL(printprettysym), oldpp);
 	value_t outp = stream_to_string(&buf);
 	fl_free_gc_handles(1);
 	return outp;
@@ -144,7 +144,7 @@
 	size_t len = cv_len(ptr(args[0]));
 	size_t dlen = cv_len(ptr(args[1]));
 	size_t ssz, tokend, tokstart, i = 0;
-	value_t first = fl->FL_NIL, c = fl->FL_NIL, last;
+	value_t first = FL(FL_NIL), c = FL(FL_NIL), last;
 	size_t junk;
 	fl_gc_handle(&first);
 	fl_gc_handle(&last);
@@ -156,7 +156,7 @@
 			tokend = i;
 		ssz = tokend - tokstart;
 		last = c; // save previous cons cell
-		c = fl_cons(cvalue_string(ssz), fl->FL_NIL);
+		c = fl_cons(cvalue_string(ssz), FL(FL_NIL));
 
 		// we've done allocation; reload movable pointers
 		s = cv_data(ptr(args[0]));
@@ -166,7 +166,7 @@
 			memmove(cv_data(ptr(car_(c))), &s[tokstart], ssz);
 
 		// link new cell
-		if(last == fl->FL_NIL)
+		if(last == FL(FL_NIL))
 			first = c;   // first time, save first cons
 		else
 			((cons_t*)ptr(last))->cdr = c;
@@ -199,7 +199,7 @@
 			bounds_error(args[0], args[2]);
 	}
 	if(endbytes == startbytes)
-		return symbol_value(fl->emptystringsym);
+		return symbol_value(FL(emptystringsym));
 	value_t ns = cvalue_string(endbytes-startbytes);
 	memmove(cv_data(ptr(ns)), s+startbytes, endbytes-startbytes);
 	return ns;
@@ -224,7 +224,7 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = (cprim_t*)ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
 	return mk_rune(toupperrune(*(Rune*)cp_data(cp)));
 }
@@ -233,7 +233,7 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
 	return mk_rune(tolowerrune(*(Rune*)cp_data(cp)));
 }
@@ -242,7 +242,7 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
 	return mk_rune(totitlerune(*(Rune*)cp_data(cp)));
 }
@@ -251,9 +251,9 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
-	return isalpharune(*(Rune*)cp_data(cp)) ? fl->FL_T : fl->FL_F;
+	return isalpharune(*(Rune*)cp_data(cp)) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("char-lower-case?", char_lower_casep)
@@ -260,9 +260,9 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
-	return islowerrune(*(Rune*)cp_data(cp)) ? fl->FL_T : fl->FL_F;
+	return islowerrune(*(Rune*)cp_data(cp)) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("char-upper-case?", char_upper_casep)
@@ -269,9 +269,9 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
-	return isupperrune(*(Rune*)cp_data(cp)) ? fl->FL_T : fl->FL_F;
+	return isupperrune(*(Rune*)cp_data(cp)) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("char-title-case?", char_title_casep)
@@ -278,9 +278,9 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
-	return istitlerune(*(Rune*)cp_data(cp)) ? fl->FL_T : fl->FL_F;
+	return istitlerune(*(Rune*)cp_data(cp)) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("char-numeric?", char_numericp)
@@ -287,9 +287,9 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
-	return isdigitrune(*(Rune*)cp_data(cp)) ? fl->FL_T : fl->FL_F;
+	return isdigitrune(*(Rune*)cp_data(cp)) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("char-whitespace?", char_whitespacep)
@@ -296,9 +296,9 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != fl->runetype)
+	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
 		type_error("rune", args[0]);
-	return isspacerune(*(Rune*)cp_data(cp)) ? fl->FL_T : fl->FL_F;
+	return isspacerune(*(Rune*)cp_data(cp)) ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("string-find", string_find)
@@ -317,12 +317,12 @@
 
 	value_t v = args[1];
 	cprim_t *cp = ptr(v);
-	if(iscprim(v) && cp_class(cp) == fl->runetype){
+	if(iscprim(v) && cp_class(cp) == FL(runetype)){
 		Rune r = *(Rune*)cp_data(cp);
 		needlesz = runetochar(cbuf, &r);
 		needle = cbuf;
 		needle[needlesz] = 0;
-	}else if(iscprim(v) && cp_class(cp) == fl->bytetype){
+	}else if(iscprim(v) && cp_class(cp) == FL(bytetype)){
 		needlesz = 1;
 		needle = cbuf;
 		needle[0] = *(char*)cp_data(cp);
@@ -335,7 +335,7 @@
 		type_error("string", args[1]);
 	}
 	if(needlesz > len-start)
-		return fl->FL_F;
+		return FL(FL_F);
 	if(needlesz == 0)
 		return size_wrap(start);
 	size_t i;
@@ -343,7 +343,7 @@
 		if(s[i] == needle[0] && memcmp(&s[i+1], needle+1, needlesz-1) == 0)
 			return size_wrap(i);
 	}
-	return fl->FL_F;
+	return FL(FL_F);
 }
 
 static unsigned long
@@ -351,7 +351,7 @@
 {
 	unsigned long radix = toulong(arg);
 	if(radix < 2 || radix > 36)
-		lerrorf(fl->ArgError, "invalid radix");
+		lerrorf(FL(ArgError), "invalid radix");
 	return radix;
 }
 
@@ -392,7 +392,7 @@
 	if(nargs == 2)
 		radix = get_radix_arg(args[1]);
 	if(!isnumtok_base(str, &n, (int)radix))
-		return fl->FL_F;
+		return FL(FL_F);
 	return n;
 }
 
@@ -401,5 +401,5 @@
 	argcount(nargs, 1);
 	char *s = tostring(args[0]);
 	size_t len = cv_len((cvalue_t*)ptr(args[0]));
-	return u8_isvalid(s, len) ? fl->FL_T : fl->FL_F;
+	return u8_isvalid(s, len) ? FL(FL_T) : FL(FL_F);
 }
--- a/table.c
+++ b/table.c
@@ -70,13 +70,13 @@
 static int
 ishashtable(value_t v)
 {
-	return iscvalue(v) && cv_class((cvalue_t*)ptr(v)) == fl->tabletype;
+	return iscvalue(v) && cv_class((cvalue_t*)ptr(v)) == FL(tabletype);
 }
 
 BUILTIN("table?", tablep)
 {
 	argcount(nargs, 1);
-	return ishashtable(args[0]) ? fl->FL_T : fl->FL_F;
+	return ishashtable(args[0]) ? FL(FL_T) : FL(FL_F);
 }
 
 static htable_t *
@@ -91,17 +91,17 @@
 {
 	size_t cnt = (size_t)nargs;
 	if(cnt & 1)
-		lerrorf(fl->ArgError, "arguments must come in pairs");
+		lerrorf(FL(ArgError), "arguments must come in pairs");
 	value_t nt;
 	// prevent small tables from being added to finalizer list
 	if(cnt <= HT_N_INLINE)
-		nt = cvalue_nofinalizer(fl->tabletype, sizeof(htable_t));
+		nt = cvalue_nofinalizer(FL(tabletype), sizeof(htable_t));
 	else
-		nt = cvalue(fl->tabletype, 2*sizeof(void*));
+		nt = cvalue(FL(tabletype), 2*sizeof(void*));
 	htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(nt));
 	htable_new(h, cnt/2);
 	int i;
-	value_t k = fl->FL_NIL, arg;
+	value_t k = FL(FL_NIL), arg;
 	FOR_ARGS(i, 0, arg, args){
 		if(i & 1)
 			equalhash_put(h, (void*)k, (void*)arg);
@@ -135,7 +135,7 @@
 static void
 key_error(value_t key)
 {
-	lerrorf(fl_list2(fl->KeyError, key), "key not found");
+	lerrorf(fl_list2(FL(KeyError), key), "key not found");
 }
 
 // (get table key [default])
@@ -158,7 +158,7 @@
 {
 	argcount(nargs, 2);
 	htable_t *h = totable(args[0]);
-	return equalhash_has(h, (void*)args[1]) ? fl->FL_T : fl->FL_F;
+	return equalhash_has(h, (void*)args[1]) ? FL(FL_T) : FL(FL_F);
 }
 
 // (del! table key)
@@ -187,7 +187,7 @@
 			// reload pointer
 			h = (htable_t*)cv_data(ptr(t));
 			if(h->size != n)
-				lerrorf(fl->EnumerationError, "table modified");
+				lerrorf(FL(EnumerationError), "table modified");
 			table = h->table;
 		}
 	}
@@ -198,6 +198,6 @@
 void
 table_init(void)
 {
-	fl->tablesym = symbol("table");
-	fl->tabletype = define_opaque_type(fl->tablesym, sizeof(htable_t), &table_vtable, nil);
+	FL(tablesym) = symbol("table");
+	FL(tabletype) = define_opaque_type(FL(tablesym), sizeof(htable_t), &table_vtable, nil);
 }
--- a/terminal_posix.c
+++ b/terminal_posix.c
@@ -55,7 +55,7 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	return termsetraw(true, cursorvisible) == 0 ? fl->FL_T : fl->FL_F;
+	return termsetraw(true, cursorvisible) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("terminal-leave-raw-mode", terminal_leave_raw_mode)
@@ -62,7 +62,7 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	return termsetraw(false, cursorvisible) == 0 ? fl->FL_T : fl->FL_F;
+	return termsetraw(false, cursorvisible) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("terminal-show-cursor", terminal_show_cursor)
@@ -69,7 +69,7 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	return termsetraw(inraw, true) == 0 ? fl->FL_T : fl->FL_F;
+	return termsetraw(inraw, true) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("terminal-hide-cursor", terminal_hide_cursor)
@@ -76,7 +76,7 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	return termsetraw(inraw, false) == 0 ? fl->FL_T : fl->FL_F;
+	return termsetraw(inraw, false) == 0 ? FL(FL_T) : FL(FL_F);
 }
 
 BUILTIN("terminal-get-size", terminal_get_size)
@@ -85,11 +85,11 @@
 	argcount(nargs, 0);
 	struct winsize s;
 	if(ioctl(STDIN_FILENO, TIOCGWINSZ, &s) < 0)
-		return fl->FL_F;
+		return FL(FL_F);
 	value_t v = mk_cons(), tex, pix;
 	car_(v) = tex = mk_cons();
 	car_(tex) = fixnum(s.ws_col);
-	cdr_(tex) = mk_cons(); car_(cdr_(tex)) = fixnum(s.ws_row); cdr_(cdr_(tex)) = fl->NIL;
+	cdr_(tex) = mk_cons(); car_(cdr_(tex)) = fixnum(s.ws_row); cdr_(cdr_(tex)) = FL(NIL);
 	int x = s.ws_xpixel, y = s.ws_ypixel;
 	bool wasraw = inraw;
 	if((x == 0 || y == 0) && isatty(STDOUT_FILENO) && termsetraw(true, cursorvisible) == 0){
@@ -124,9 +124,9 @@
 		if(!wasraw)
 			termsetraw(false, cursorvisible);
 	}
-	cdr_(v) = pix = mk_cons(); cdr_(pix) = fl->NIL;
+	cdr_(v) = pix = mk_cons(); cdr_(pix) = FL(NIL);
 	car_(pix) = mk_cons(); pix = car_(pix);
 	car_(pix) = fixnum(x);
-	cdr_(pix) = mk_cons(); car_(cdr_(pix)) = fixnum(y); cdr_(cdr_(pix)) = fl->NIL;
+	cdr_(pix) = mk_cons(); car_(cdr_(pix)) = fixnum(y); cdr_(cdr_(pix)) = FL(NIL);
 	return v;
 }
--- a/types.c
+++ b/types.c
@@ -13,11 +13,11 @@
 		if(ft != nil)
 			return ft;
 	}
-	void **bp = equalhash_bp(&fl->TypeTable, (void*)t);
+	void **bp = equalhash_bp(&FL(TypeTable), (void*)t);
 	if(*bp != HT_NOTFOUND)
 		return *bp;
 
-	int align, isarray = iscons(t) && car_(t) == fl->arraysym && iscons(cdr_(t));
+	int align, isarray = iscons(t) && car_(t) == FL(arraysym) && iscons(cdr_(t));
 	size_t sz;
 	if(isarray && !iscons(cdr_(cdr_(t)))){
 		// special case: incomplete array type
@@ -41,13 +41,13 @@
 			fltype_t *eltype = get_type(car_(cdr_(t)));
 			if(eltype->size == 0){
 				LLT_FREE(ft);
-				lerrorf(fl->ArgError, "invalid array element type");
+				lerrorf(FL(ArgError), "invalid array element type");
 			}
 			ft->elsz = eltype->size;
 			ft->eltype = eltype;
 			ft->init = cvalue_array_init;
 			//eltype->artype = ft; -- this is a bad idea since some types carry array sizes
-		}else if(car_(t) == fl->enumsym){
+		}else if(car_(t) == FL(enumsym)){
 			ft->numtype = T_INT32;
 			ft->init = cvalue_enum_init;
 		}
@@ -61,7 +61,7 @@
 {
 	fltype_t *et = get_type(eltype);
 	if(et->artype == nil)
-		et->artype = get_type(fl_list2(fl->arraysym, eltype));
+		et->artype = get_type(fl_list2(FL(arraysym), eltype));
 	return et->artype;
 }
 
@@ -81,7 +81,7 @@
 void
 relocate_typetable(void)
 {
-	htable_t *h = &fl->TypeTable;
+	htable_t *h = &FL(TypeTable);
 	size_t i;
 	void *nv;
 	for(i = 0; i < h->size; i += 2){