diff lwasm/pseudo.c @ 0:2c24602be78f

Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author lost@l-w.ca
date Wed, 19 Jan 2011 22:27:17 -0700
parents
children 7317fbe024af
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pseudo.c	Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,1143 @@
+/*
+pseudo.c
+Copyright © 2010 William Astle
+
+This file is part of LWASM.
+
+LWASM is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <stdio.h>
+
+#include "lwasm.h"
+#include "instab.h"
+#include "input.h"
+
+#include "lw_string.h"
+
+extern void register_struct_entry(asmstate_t *as, line_t *l, int size, structtab_t *ss);
+
+// for "end"
+PARSEFUNC(pseudo_parse_end)
+{
+	lw_expr_t addr;
+	
+	as -> endseen = 1;
+	l -> len = 0;
+	
+	if (as -> output_format != OUTPUT_DECB)
+	{
+		skip_operand(p);
+		return;
+	}
+	
+	if (!**p)
+	{
+		addr = lw_expr_build(lw_expr_type_int, 0);
+	}
+	else
+	{
+		addr = lwasm_parse_expr(as, p);
+	}
+	if (!addr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+		addr = lw_expr_build(lw_expr_type_int, 0);
+	}
+	lwasm_save_expr(l, 0, addr);
+}
+
+EMITFUNC(pseudo_emit_end)
+{
+	lw_expr_t addr;
+	
+	addr = lwasm_fetch_expr(l, 0);
+	
+	if (addr)
+	{
+		if (!lw_expr_istype(addr, lw_expr_type_int))
+			lwasm_register_error(as, l, "Exec address not constant!");
+		else
+			as -> execaddr = lw_expr_intval(addr);
+	}
+	as -> endseen = 1;
+}
+
+PARSEFUNC(pseudo_parse_fcb)
+{
+	int i = 0;
+	lw_expr_t e;
+	
+	for (;;)
+	{
+		e = lwasm_parse_expr(as, p);
+		if (!e)
+		{
+			lwasm_register_error(as, l, "Bad expression (#%s)", i);
+			break;
+		}
+		lwasm_save_expr(l, i++, e);
+		if (**p != ',')
+			break;
+		(*p)++;
+	}
+	
+	l -> len = i;
+}
+
+EMITFUNC(pseudo_emit_fcb)
+{
+	int i;
+	lw_expr_t e;
+	int v;
+	
+	for (i = 0; i < l -> len; i++)
+	{
+		e = lwasm_fetch_expr(l, i);
+		lwasm_emitexpr(l, e, 1);
+	}
+}
+
+PARSEFUNC(pseudo_parse_fdb)
+{
+	int i = 0;
+	lw_expr_t e;
+	
+	for (;;)
+	{
+		e = lwasm_parse_expr(as, p);
+		if (!e)
+		{
+			lwasm_register_error(as, l, "Bad expression (#%d)", i);
+			break;
+		}
+		lwasm_save_expr(l, i++, e);
+		if (**p != ',')
+			break;
+		(*p)++;
+	}
+	
+	l -> len = i * 2;
+}
+
+EMITFUNC(pseudo_emit_fdb)
+{
+	int i;
+	lw_expr_t e;
+	int v;
+	
+	for (i = 0; i < (l -> len)/2; i++)
+	{
+		e = lwasm_fetch_expr(l, i);
+		lwasm_emitexpr(l, e, 2);
+	}
+}
+
+PARSEFUNC(pseudo_parse_fqb)
+{
+	int i = 0;
+	lw_expr_t e;
+	
+	for (;;)
+	{
+		e = lwasm_parse_expr(as, p);
+		if (!e)
+		{
+			lwasm_register_error(as, l, "Bad expression (#%s)", i);
+			break;
+		}
+		lwasm_save_expr(l, i++, e);
+		if (**p != ',')
+			break;
+		(*p)++;
+	}
+	
+	l -> len = i * 4;
+}
+
+EMITFUNC(pseudo_emit_fqb)
+{
+	int i;
+	lw_expr_t e;
+	int v;
+	
+	for (i = 0; i < (l -> len)/4; i++)
+	{
+		e = lwasm_fetch_expr(l, i);
+		lwasm_emitexpr(l, e, 4);
+	}
+}
+
+PARSEFUNC(pseudo_parse_fcc)
+{
+	char delim;
+	int i;
+	
+	if (!**p)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	delim = **p;
+	(*p)++;
+	
+	for (i = 0; (*p)[i] && (*p)[i] != delim; i++)
+		/* do nothing */ ;
+	
+	if ((*p)[i] != delim)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	l -> lstr = lw_strndup(*p, i);
+	(*p) += i + 1;
+	
+	l -> len = i;
+}
+
+EMITFUNC(pseudo_emit_fcc)
+{
+	int i;
+	
+	for (i = 0; i < l -> len; i++)
+		lwasm_emit(l, l -> lstr[i]);
+}
+
+PARSEFUNC(pseudo_parse_fcs)
+{
+	char delim;
+	int i;
+	
+	if (!**p)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	delim = **p;
+	(*p)++;
+	
+	for (i = 0; (*p)[i] && (*p)[i] != delim; i++)
+		/* do nothing */ ;
+	
+	if ((*p)[i] != delim)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	l -> lstr = lw_strndup(*p, i);
+	(*p) += i + 1;
+	
+	l -> len = i;
+}
+
+EMITFUNC(pseudo_emit_fcs)
+{
+	int i;
+	
+	for (i = 0; i < l -> len - 1; i++)
+		lwasm_emit(l, l -> lstr[i]);
+	lwasm_emit(l, l -> lstr[i] | 0x80);
+}
+
+PARSEFUNC(pseudo_parse_fcn)
+{
+	char delim;
+	int i;
+	
+	if (!**p)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	delim = **p;
+	(*p)++;
+	
+	for (i = 0; (*p)[i] && (*p)[i] != delim; i++)
+		/* do nothing */ ;
+	
+	if ((*p)[i] != delim)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	l -> lstr = lw_strndup(*p, i);
+	(*p) += i + 1;
+	
+	l -> len = i + 1;
+}
+
+EMITFUNC(pseudo_emit_fcn)
+{
+	int i;
+	
+	for (i = 0; i < (l -> len - 1); i++)
+		lwasm_emit(l, l -> lstr[i]);
+	lwasm_emit(l, 0);
+}
+
+PARSEFUNC(pseudo_parse_rmb)
+{
+	lw_expr_t expr;
+	
+	expr = lwasm_parse_expr(as, p);
+	if (!expr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+	}
+
+	l -> lint = 0;
+	if (as -> instruct)
+	{
+		lwasm_reduce_expr(as, expr);
+		if (!lw_expr_istype(expr, lw_expr_type_int))
+		{
+			lwasm_register_error(as, l, "Expression must be constant at parse time");
+		}
+		else
+		{
+			int e;
+			e = lw_expr_intval(expr);
+			register_struct_entry(as, l, e, NULL);
+			l -> len = 0;
+			l -> lint = 1;
+			l -> symset = 1;
+		}
+	}
+	
+	lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_rmb)
+{
+	lw_expr_t expr;
+	
+	if (l -> lint)
+		return;
+	
+	if (l -> len >= 0)
+		return;
+	
+	expr = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		l -> len = lw_expr_intval(expr);
+	}
+}
+
+EMITFUNC(pseudo_emit_rmb)
+{
+	if (l -> lint)
+		return;
+
+	if (l -> len < 0)
+		lwasm_register_error(as, l, "Expression not constant");
+}
+
+PARSEFUNC(pseudo_parse_rmd)
+{
+	lw_expr_t expr;
+	
+	l -> lint = 0;
+	expr = lwasm_parse_expr(as, p);
+	if (!expr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+	}
+	
+	if (as -> instruct)
+	{
+		lwasm_reduce_expr(as, expr);
+		if (!lw_expr_istype(expr, lw_expr_type_int))
+		{
+			lwasm_register_error(as, l, "Expression must be constant at parse time");
+		}
+		else
+		{
+			int e;
+			e = lw_expr_intval(expr) * 2;
+			register_struct_entry(as, l, e, NULL);
+			l -> len = 0;
+			l -> symset = 1;
+			l -> lint = 1;
+		}
+	}
+	lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_rmd)
+{
+	lw_expr_t expr;
+	
+	if (l -> lint)
+		return;
+	
+	if (l -> len >= 0)
+		return;
+	
+	expr = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		l -> len = lw_expr_intval(expr) * 2;
+	}
+}
+
+EMITFUNC(pseudo_emit_rmd)
+{
+	if (l -> lint)
+		return;
+
+	if (l -> len < 0)
+		lwasm_register_error(as, l, "Expression not constant");
+}
+
+
+PARSEFUNC(pseudo_parse_rmq)
+{
+	lw_expr_t expr;
+	
+	l -> lint = 0;
+	expr = lwasm_parse_expr(as, p);
+	if (!expr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+	}
+	if (as -> instruct)
+	{
+		lwasm_reduce_expr(as, expr);
+		if (!lw_expr_istype(expr, lw_expr_type_int))
+		{
+			lwasm_register_error(as, l, "Expression must be constant at parse time");
+		}
+		else
+		{
+			int e;
+			e = lw_expr_intval(expr) * 4;
+			register_struct_entry(as, l, e, NULL);
+			l -> len = 0;
+			l -> symset = 1;
+			l -> lint = 1;
+		}
+	}
+	
+	lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_rmq)
+{
+	lw_expr_t expr;
+
+	if (l -> lint)
+		return;
+	
+	if (l -> len >= 0)
+		return;
+	
+	expr = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		l -> len = lw_expr_intval(expr) * 4;
+	}
+}
+
+EMITFUNC(pseudo_emit_rmq)
+{
+	if (l -> lint)
+		return;
+
+	if (l -> len < 0)
+		lwasm_register_error(as, l, "Expression not constant");
+}
+
+
+PARSEFUNC(pseudo_parse_zmq)
+{
+	lw_expr_t expr;
+	
+	expr = lwasm_parse_expr(as, p);
+	if (!expr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+	}
+	
+	lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_zmq)
+{
+	lw_expr_t expr;
+	
+	if (l -> len >= 0)
+		return;
+	
+	expr = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		l -> len = lw_expr_intval(expr) * 4;
+	}
+}
+
+EMITFUNC(pseudo_emit_zmq)
+{
+	int i;
+
+	if (l -> len < 0)
+	{
+		lwasm_register_error(as, l, "Expression not constant");
+		return;
+	}
+
+	for (i = 0; i < l -> len; i++)
+		lwasm_emit(l, 0);	
+}
+
+
+PARSEFUNC(pseudo_parse_zmd)
+{
+	lw_expr_t expr;
+	
+	expr = lwasm_parse_expr(as, p);
+	if (!expr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+	}
+	
+	lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_zmd)
+{
+	lw_expr_t expr;
+	
+	if (l -> len >= 0)
+		return;
+	
+	expr = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		l -> len = lw_expr_intval(expr) * 2;
+	}
+}
+
+EMITFUNC(pseudo_emit_zmd)
+{
+	int i;
+
+	if (l -> len < 0)
+	{
+		lwasm_register_error(as, l, "Expression not constant");
+		return;
+	}
+
+	for (i = 0; i < l -> len; i++)
+		lwasm_emit(l, 0);	
+}
+
+PARSEFUNC(pseudo_parse_zmb)
+{
+	lw_expr_t expr;
+	
+	expr = lwasm_parse_expr(as, p);
+	if (!expr)
+	{
+		lwasm_register_error(as, l, "Bad expression");
+	}
+	
+	lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_zmb)
+{
+	lw_expr_t expr;
+	
+	if (l -> len >= 0)
+		return;
+	
+	expr = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		l -> len = lw_expr_intval(expr);
+	}
+}
+
+EMITFUNC(pseudo_emit_zmb)
+{
+	int i;
+
+	if (l -> len < 0)
+	{
+		lwasm_register_error(as, l, "Expression not constant");
+		return;
+	}
+
+	for (i = 0; i < l -> len; i++)
+		lwasm_emit(l, 0);	
+}
+
+PARSEFUNC(pseudo_parse_org)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	e = lwasm_parse_expr(as, p);
+	if (!e)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	lw_expr_destroy(l -> addr);
+	l -> addr = e;
+	l -> len = 0;
+}
+
+PARSEFUNC(pseudo_parse_equ)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (!(l -> sym))
+	{
+		lwasm_register_error(as, l, "Missing symbol");
+		return;
+	}
+	
+	e = lwasm_parse_expr(as, p);
+	if (!e)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	register_symbol(as, l, l -> sym, e, symbol_flag_none);
+	l -> symset = 1;
+	l -> dptr = lookup_symbol(as, l, l -> sym);
+}
+
+PARSEFUNC(pseudo_parse_set)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (!(l -> sym))
+	{
+		lwasm_register_error(as, l, "Missing symbol");
+		return;
+	}
+	
+	e = lwasm_parse_expr(as, p);
+	if (!e)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	register_symbol(as, l, l -> sym, e, symbol_flag_set);
+	l -> symset = 1;
+	l -> dptr = lookup_symbol(as, l, l -> sym);
+}
+
+PARSEFUNC(pseudo_parse_setdp)
+{
+	lw_expr_t e;
+
+	l -> len = 0;
+	
+	if (as -> output_format == OUTPUT_OBJ)
+	{
+		lwasm_register_error(as, l, "SETDP not permitted for object target");
+		return;
+	}
+	
+	e = lwasm_parse_expr(as, p);
+	if (!e)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	if (!lw_expr_istype(e, lw_expr_type_int))
+	{
+		lwasm_register_error(as, l, "SETDP must be constant on pass 1");
+		return;
+	}
+	l -> dpval = lw_expr_intval(e) & 0xff;
+	l -> dshow = l -> dpval;
+	l -> dsize = 1;
+}
+
+PARSEFUNC(pseudo_parse_ifp1)
+{
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+	
+	lwasm_register_warning(as, l, "IFP1 if is not supported; ignoring");
+	
+}
+
+PARSEFUNC(pseudo_parse_ifp2)
+{
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+	
+	lwasm_register_warning(as, l, "IFP2 if is not supported; ignoring");
+}
+
+PARSEFUNC(pseudo_parse_ifeq)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) != 0)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_ifne)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) == 0)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+
+PARSEFUNC(pseudo_parse_ifgt)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) <= 0)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_ifge)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) < 0)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_iflt)
+{
+	lw_expr_t e;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) >= 0)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_ifle)
+{
+	lw_expr_t e;
+
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) > 0)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_endc)
+{
+	l -> len = 0;
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount--;
+		if (as -> skipcount <= 0)
+			as -> skipcond = 0;
+	}
+}
+
+PARSEFUNC(pseudo_parse_else)
+{
+	l -> len = 0;
+	
+	if (as -> skipmacro)
+		return;
+	
+	if (as -> skipcond)
+	{
+		if (as -> skipcount == 1)
+		{
+			as -> skipcount = 0;
+			as -> skipcond = 0;
+		}
+		return;
+	}
+	as -> skipcond = 1;
+	as -> skipcount = 1;
+}
+
+PARSEFUNC(pseudo_parse_ifdef)
+{
+	char *sym;
+	int i;
+	struct symtabe *s;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	for (i = 0; (*p)[i] && !isspace((*p)[i]); i++)
+		/* do nothing */ ;
+	
+	sym = lw_strndup(*p, i);
+	
+	s = lookup_symbol(as, l, sym);
+	
+	lw_free(sym);
+	
+	if (!s)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_ifndef)
+{
+	char *sym;
+	int i;
+	struct symtabe *s;
+	
+	l -> len = 0;
+	
+	if (as -> skipcond && !(as -> skipmacro))
+	{
+		as -> skipcount++;
+		skip_operand(p);
+		return;
+	}
+
+	for (i = 0; (*p)[i] && !isspace((*p)[i]); i++)
+		/* do nothing */ ;
+	
+	sym = lw_strndup(*p, i);
+	(*p) += i;
+	
+	s = lookup_symbol(as, l, sym);
+	
+	lw_free(sym);
+
+	if (s)
+	{
+		as -> skipcond = 1;
+		as -> skipcount = 1;
+	}
+}
+
+PARSEFUNC(pseudo_parse_error)
+{
+	lwasm_register_error(as, l, "User error: %s", *p);
+	skip_operand(p);
+}
+
+PARSEFUNC(pseudo_parse_warning)
+{
+	lwasm_register_warning(as, l, "User warning: %s", *p);
+	skip_operand(p);
+}
+
+PARSEFUNC(pseudo_parse_includebin)
+{
+	char *fn, *p2;
+	int delim = 0;
+	FILE *fp;
+	long flen;
+	
+	if (!**p)
+	{
+		lwasm_register_error(as, l, "Missing filename");
+		return;
+	}
+	
+	if (**p == '"' || **p == '\'')
+	{
+		delim = **p;
+		(*p)++;
+
+		for (p2 = *p; *p2 && *p2 != delim; p2++)
+			/* do nothing */ ;
+	}
+	else
+	{
+		for (p2 = *p; *p2 && !isspace(*p2); p2++)
+			/* do nothing */ ;
+	}
+	fn = lw_strndup(*p, p2 - *p);
+	
+	if (delim && **p)
+		(*p)++;
+	
+	fp = input_open_standalone(as, fn);
+	if (!fp)
+	{
+		lwasm_register_error(as, l, "Cannot open file");
+		lw_free(fn);
+		return;
+	}
+	
+	l -> lstr = fn;
+	
+	fseek(fp, 0, SEEK_END);
+	flen = ftell(fp);
+	fclose(fp);
+
+	l -> len = flen;
+}
+
+EMITFUNC(pseudo_emit_includebin)
+{
+	FILE *fp;
+	int c;
+	
+	fp = input_open_standalone(as, l -> lstr);
+	if (!fp)
+	{
+		lwasm_register_error(as, l, "Cannot open file (emit)!");
+		return;
+	}
+	
+	for (;;)
+	{
+		c = fgetc(fp);
+		if (c == EOF)
+		{
+			fclose(fp);
+			return;
+		}
+		lwasm_emit(l, c);
+	}
+}
+
+PARSEFUNC(pseudo_parse_include)
+{
+	char *fn, *p2;
+	char *p3;
+	int delim = 0;
+	
+	if (!**p)
+	{
+		lwasm_register_error(as, l, "Missing filename");
+		return;
+	}
+	
+	if (**p == '"' || **p == '\'')
+	{
+		delim = **p;
+		(*p)++;
+
+		for (p2 = *p; *p2 && *p2 != delim; p2++)
+			/* do nothing */ ;
+	}
+	else
+	{
+		for (p2 = *p; *p2 && !isspace(*p2); p2++)
+			/* do nothing */ ;
+	}
+	fn = lw_strndup(*p, p2 - *p);
+	(*p) = p2;
+	if (delim && **p)
+		(*p)++;
+	
+	0 == asprintf(&p3, "include:%s", fn);
+	input_open(as, p3);
+	lw_free(p3);
+
+	l -> len = 0;
+}
+
+PARSEFUNC(pseudo_parse_align)
+{
+	lw_expr_t e;
+	if (!**p)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	e = lwasm_parse_expr(as, p);
+	
+	if (!e)
+	{
+		lwasm_register_error(as, l, "Bad operand");
+		return;
+	}
+	
+	lwasm_save_expr(l, 0, e);
+	
+	if (**p == ',')
+	{
+		e = lwasm_parse_expr(as, p);
+	}
+	else
+	{
+		e = lw_expr_build(lw_expr_type_int, 0);
+	}
+	if (!e)
+	{
+		lwasm_register_error(as, l, "Bad padding");
+		return;
+	}
+	
+	lwasm_save_expr(l, 1, e);
+}
+
+RESOLVEFUNC(pseudo_resolve_align)
+{
+	lw_expr_t e;
+	int align;
+
+	e = lwasm_fetch_expr(l, 0);
+	
+	if (lw_expr_istype(e, lw_expr_type_int))
+	{
+		align = lw_expr_intval(e);
+		if (align < 1)
+		{
+			lwasm_register_error(as, l, "Invalid alignment");
+			return;
+		}
+	}
+	
+	if (lw_expr_istype(l -> addr, lw_expr_type_int))
+	{
+		int a;
+		a = lw_expr_intval(l -> addr);
+		if (a % align == 0)
+		{
+			l -> len = 0;
+			return;
+		}
+		l -> len = align - (a % align);
+		return;
+	}
+}
+
+EMITFUNC(pseudo_emit_align)
+{
+	lw_expr_t e;
+	int i;
+	
+	e = lwasm_fetch_expr(l, 1);
+	for (i = 0; i < l -> len; i++)
+	{
+		lwasm_emitexpr(l, e, 1);
+	}
+}