changeset 389:fbb7bfed8076

Added in structure support and fixed up some warts in the listing code (by adding more warts)
author lost@l-w.ca
date Wed, 14 Jul 2010 22:33:55 -0600
parents 8991eb507d2d
children 027d7fbcdcfc
files lwasm/Makefile.am lwasm/instab.c lwasm/instab.h lwasm/list.c lwasm/lwasm.h lwasm/pass1.c lwasm/pseudo.c lwasm/struct.c lwasm/symbol.c
diffstat 9 files changed, 399 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/lwasm/Makefile.am	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/Makefile.am	Wed Jul 14 22:33:55 2010 -0600
@@ -4,6 +4,7 @@
 	instab.c symbol.c macro.c pass2.c pass3.c pass4.c pass5.c pass6.c \
 	insn_inh.c insn_rtor.c insn_tfm.c insn_rlist.c insn_rel.c \
 	insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c \
-	pseudo.c section.c os9.c pass7.c debug.c output.c list.c
+	pseudo.c section.c os9.c pass7.c debug.c output.c list.c \
+	struct.c
 lwasm_LDADD = -L$(top_builddir)/lib -L$(top_srcdir)/lib -L$(top_builddir)/lwlib -L$(top_srcdir)/lwlib -lgnu -llw
 EXTRA_DIST =  lwasm.h input.h instab.h
--- a/lwasm/instab.c	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/instab.c	Wed Jul 14 22:33:55 2010 -0600
@@ -285,6 +285,14 @@
 extern RESOLVEFUNC(pseudo_resolve_align);
 extern EMITFUNC(pseudo_emit_align);
 
+extern PARSEFUNC(pseudo_parse_struct);
+#define pseudo_resolve_struct NULL
+#define pseudo_emit_struct NULL
+
+extern PARSEFUNC(pseudo_parse_endstruct);
+#define pseudo_resolve_endstruct NULL
+#define pseudo_emit_endstruct NULL
+
 instab_t instab[] =
 {
 
@@ -555,9 +563,9 @@
 	{ "export",		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_export,	pseudo_resolve_export,			pseudo_emit_export,			lwasm_insn_setsym},
 	{ "extdep",		{	-1,		-1,		-1,		-1 },	pseudo_parse_extdep,	pseudo_resolve_extdep,			pseudo_emit_extdep,			lwasm_insn_setsym},
 
-	{ "rmb", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_normal},
-	{ "rmd", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_rmd,		pseudo_resolve_rmd,				pseudo_emit_rmd,			lwasm_insn_normal},
-	{ "rmq", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_rmq,		pseudo_resolve_rmq,				pseudo_emit_rmq,			lwasm_insn_normal},
+	{ "rmb", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_struct},
+	{ "rmd", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_rmd,		pseudo_resolve_rmd,				pseudo_emit_rmd,			lwasm_insn_struct},
+	{ "rmq", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_rmq,		pseudo_resolve_rmq,				pseudo_emit_rmq,			lwasm_insn_struct},
 
 	{ "zmb", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_zmb,		pseudo_resolve_zmb,				pseudo_emit_zmb,			lwasm_insn_normal},
 	{ "zmd", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_zmd,		pseudo_resolve_zmd,				pseudo_emit_zmd,			lwasm_insn_normal},
@@ -608,6 +616,9 @@
 	{ "ends",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_endsection,pseudo_resolve_endsection,		pseudo_emit_endsection,		lwasm_insn_normal},
 	{ "endsect",	{	-1, 	-1, 	-1, 	-1},	pseudo_parse_endsection,pseudo_resolve_endsection,		pseudo_emit_endsection,		lwasm_insn_normal},
 	{ "endsection",	{	-1,		-1, 	-1, 	-1},	pseudo_parse_endsection,pseudo_resolve_endsection,		pseudo_emit_endsection,		lwasm_insn_normal},
+
+	{ "struct",		{	-1,		-1,		-1,		-1},	pseudo_parse_struct,	pseudo_resolve_struct,			pseudo_emit_struct,			lwasm_insn_normal},
+	{ "endstruct",	{	-1,		-1,		-1,		-1},	pseudo_parse_endstruct,	pseudo_resolve_endstruct,		pseudo_emit_endstruct,		lwasm_insn_struct},
 	
 
 	{ "pragma",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_pragma,	pseudo_resolve_pragma,			pseudo_emit_pragma,			lwasm_insn_normal},
@@ -643,9 +654,9 @@
 	{ ".asciz",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_fcn,		pseudo_resolve_fcn,				pseudo_emit_fcn,			lwasm_insn_normal},
 	{ ".strz",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_fcn,		pseudo_resolve_fcn,				pseudo_emit_fcn,			lwasm_insn_normal},
 
-	{ ".blkb",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_normal},
-	{ ".ds",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_normal},
-	{ ".rs",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_normal},
+	{ ".blkb",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_struct},
+	{ ".ds",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_struct},
+	{ ".rs",		{	-1, 	-1, 	-1, 	-1},	pseudo_parse_rmb,		pseudo_resolve_rmb,				pseudo_emit_rmb,			lwasm_insn_struct},
 
 	// for compatibility
 	{ ".end", 		{	-1, 	-1, 	-1, 	-1 },	pseudo_parse_end,		pseudo_resolve_end,				pseudo_emit_end,			lwasm_insn_normal},
--- a/lwasm/instab.h	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/instab.h	Wed Jul 14 22:33:55 2010 -0600
@@ -38,11 +38,12 @@
 
 enum
 {
-	lwasm_insn_normal = 0,
 	lwasm_insn_cond = 1,		/* conditional instruction */
 	lwasm_insn_endm = 2,		/* end of macro */
 	lwasm_insn_setsym = 4,		/* insn sets symbol address */
-	lwasm_insn_is6309 = 8		/* insn is 6309 only */
+	lwasm_insn_is6309 = 8,		/* insn is 6309 only */
+	lwasm_insn_struct = 16,		/* insn allowed in a struct */
+	lwasm_insn_normal = 0
 };
 
 
--- a/lwasm/list.c	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/list.c	Wed Jul 14 22:33:55 2010 -0600
@@ -55,15 +55,53 @@
 	{
 		if (cl -> len < 1)
 		{
-			fprintf(of, "                      ");
+			if (cl -> soff >= 0)
+			{
+				fprintf(of, "%04X                  ", cl -> soff & 0xffff);
+			}
+			else if (cl -> dshow >= 0)
+			{
+				if (cl -> dsize == 1)
+				{
+					fprintf(of, "     %02X                 ", cl -> dshow & 0xff);
+				}
+				else
+				{
+					fprintf(of, "     %04X               ", cl -> dshow & 0xff);
+				}
+			}
+			else if (cl -> dptr)
+			{
+				lw_expr_t te;
+				te = lw_expr_copy(cl -> dptr -> value);
+				as -> exportcheck = 1;
+				as -> csect = cl -> csect;
+				lwasm_reduce_expr(as, te);
+				as -> exportcheck = 0;
+				if (lw_expr_istype(te, lw_expr_type_int))
+				{
+					fprintf(of, "     %04X             ", lw_expr_intval(te) & 0xffff);
+				}
+				else
+				{
+					fprintf(of, "     ????             ");
+				}
+				lw_expr_destroy(te);
+			}
+			else
+			{
+				fprintf(of, "                      ");
+			}
 		}
 		else
 		{
 			lw_expr_t te;
 			te = lw_expr_copy(cl -> addr);
 			as -> exportcheck = 1;
+			as -> csect = cl -> csect;
 			lwasm_reduce_expr(as, te);
 			as -> exportcheck = 0;
+//			fprintf(of, "%s\n", lw_expr_print(te));
 			fprintf(of, "%04X ", lw_expr_intval(te) & 0xffff);
 			lw_expr_destroy(te);
 			for (i = 0; i < cl -> outputl && i < 8; i++)
@@ -76,7 +114,7 @@
 			}
 			fprintf(of, " ");
 		}
-		fprintf(of, "%15s:%05d %s\n", cl -> linespec, cl -> lineno, cl -> ltext);
+		fprintf(of, "(%31.31s):%05d %s\n", cl -> linespec, cl -> lineno, cl -> ltext);
 		if (cl -> outputl > 8)
 		{
 			for (i = 8; i < cl -> outputl; i++)
--- a/lwasm/lwasm.h	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/lwasm.h	Wed Jul 14 22:33:55 2010 -0600
@@ -166,11 +166,16 @@
 	char *ltext;						// line number
 	char *linespec;						// line spec
 	int lineno;							// line number
+	int soff;							// struct offset (for listings)
+	int dshow;							// data value to show (for listings)
+	int dsize;							// set to 1 for 8 bit dshow value
+	struct symtabe *dptr;				// symbol value to display
 };
 
 enum
 {
 	symbol_flag_set = 1,				// symbol was used with "set"
+	symbol_flag_nocheck = 2,			// do not check symbol characters
 	symbol_flag_none = 0				// no flags
 };
 
@@ -198,6 +203,26 @@
 	int numlines;						// number lines in macro
 	macrotab_t *next;					// next macro in list
 };
+
+typedef struct structtab_s structtab_t;
+typedef struct structtab_field_s structtab_field_t;
+
+struct structtab_field_s
+{
+	char *name;							// structure field name - NULL for anonymous
+	int size;							// structure field size
+	structtab_t *substruct;				// sub structure if there is one
+	structtab_field_t *next;			// next field entry
+};
+
+struct structtab_s
+{
+	char *name;							// name of structure
+	int size;							// number of bytes taken by struct
+	structtab_field_t *fields;			// fields in the structure
+	structtab_t *next;					// next structure
+};
+
 struct asmstate_s
 {
 	int output_format;					// output format
@@ -208,6 +233,7 @@
 	int pragmas;						// pragmas currently in effect
 	int errorcount;						// number of errors encountered
 	int inmacro;						// are we in a macro?
+	int instruct;						// are w in a structure?
 	int skipcond;						// skipping a condition?
 	int skipcount;						// depth of "skipping"
 	int skipmacro;						// are we skipping in a macro?	
@@ -239,6 +265,9 @@
 	lw_stringlist_t include_list;		// include paths
 	lw_stack_t file_dir;				// stack of the "current file" dir
 	lw_stack_t includelist;
+
+	structtab_t *structs;				// defined structures
+	structtab_t *cstruct;				// current structure
 	
 	int exportcheck;					// set if we need to collapse out the section base to 0
 };
--- a/lwasm/pass1.c	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/pass1.c	Wed Jul 14 22:33:55 2010 -0600
@@ -31,6 +31,9 @@
 #include "instab.h"
 #include "input.h"
 
+extern int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc);
+extern int expand_struct(asmstate_t *as, line_t *l, char **p, char *opc);
+
 /*
 pass 1: parse the lines
 
@@ -91,6 +94,10 @@
 		cl -> pragmas = as -> pragmas;
 		cl -> context = as -> context;
 		cl -> ltext = lw_strdup(line);
+		cl -> soff = -1;
+		cl -> dshow = -1;
+		cl -> dsize = 0;
+		cl -> dptr = NULL;
 		as -> cl = cl;
 		if (!as -> line_tail)
 		{
@@ -226,7 +233,7 @@
 			// do nothing
 			if (as -> skipcond && !(instab[opnum].flags & lwasm_insn_cond))
 				goto linedone;
-        			
+        	
 			if (instab[opnum].opcode == NULL)
 			{
 				cl -> insn = -1;
@@ -236,7 +243,11 @@
 					if (expand_macro(as, cl, &p1, sym) != 0)
 					{
 						// macro expansion failed
-						lwasm_register_error(as, cl, "Bad opcode");
+						if (expand_struct(as, cl, &p1, sym) != 0)
+						{
+							// structure expansion failed
+							lwasm_register_error(as, cl, "Bad opcode");
+						}
 					}
 				}
 			}
@@ -246,13 +257,20 @@
 				// no parse func means operand doesn't matter
 				if (instab[opnum].parse)
 				{
-					cl -> len = -1;
-					// call parse function
-					(instab[opnum].parse)(as, cl, &p1);
+					if (as -> instruct == 0 || instab[opnum].flags & lwasm_insn_struct)
+					{
+						cl -> len = -1;
+						// call parse function
+						(instab[opnum].parse)(as, cl, &p1);
 					
-					if (*p1 && !isspace(*p1))
+						if (*p1 && !isspace(*p1))
+						{
+							// flag bad operand error
+							lwasm_register_error(as, cl, "Bad operand (%s)", p1);
+						}
+					}
+					else if (as -> instruct == 1)
 					{
-						// flag bad operand error
 						lwasm_register_error(as, cl, "Bad operand (%s)", p1);
 					}
 				}
--- a/lwasm/pseudo.c	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/pseudo.c	Wed Jul 14 22:33:55 2010 -0600
@@ -29,6 +29,8 @@
 
 #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)
 {
@@ -302,6 +304,22 @@
 	{
 		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);
+			register_struct_entry(as, l, e, NULL);
+			l -> len = 0;
+		}
+	}
 	
 	lwasm_save_expr(l, 0, expr);
 }
@@ -337,6 +355,21 @@
 		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;
+		}
+	}
 	lwasm_save_expr(l, 0, expr);
 }
 
@@ -371,6 +404,21 @@
 	{
 		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;
+		}
+	}
 	
 	lwasm_save_expr(l, 0, expr);
 }
@@ -563,6 +611,7 @@
 	
 	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)
@@ -586,6 +635,7 @@
 	
 	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)
@@ -613,6 +663,8 @@
 		return;
 	}
 	l -> dpval = lw_expr_intval(e) & 0xff;
+	l -> dshow = l -> dpval;
+	l -> dsize = 1;
 }
 
 PARSEFUNC(pseudo_parse_ifp1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/struct.c	Wed Jul 14 22:33:55 2010 -0600
@@ -0,0 +1,218 @@
+/*
+struct.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/>.
+
+Contains stuff associated with structure processing
+*/
+
+#include <config.h>
+
+#include <string.h>
+
+#include <lw_alloc.h>
+#include <lw_string.h>
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(pseudo_parse_struct)
+{
+	structtab_t *s;
+	
+	if (as -> instruct)
+	{
+		lwasm_register_error(as, l, "Attempt to define a structure inside a structure");
+		return;
+	}
+	
+	if (l -> sym == NULL)
+	{
+		lwasm_register_error(as, l, "Structure definition with no effect - no symbol");
+		return;
+	}
+	
+	for (s = as -> structs; s; s = s -> next)
+	{
+		if (!strcmp(s -> name, l -> sym))	
+			break;
+	}
+	
+	if (s)
+	{
+		lwasm_register_error(as, l, "Duplicate structure definition");
+		return;
+	}
+	
+	as -> instruct = 1;
+	
+	s = lw_alloc(sizeof(structtab_t));
+	s -> name = lw_strdup(l -> sym);
+	s -> next = as -> structs;
+	s -> fields = NULL;
+	s -> size = 0;
+	as -> structs = s;
+	as -> cstruct = s;
+	
+	skip_operand(p);
+	
+	l -> len = 0;
+	l -> symset = 1;
+}
+
+void pseudo_endstruct_aux(asmstate_t *as, line_t *l, structtab_field_t *e, const char *prefix, int *coff)
+{
+	char *symname = NULL;
+	lw_expr_t te1, te2;
+	
+	while (e)
+	{
+		if (e -> name)
+			0 == asprintf(&symname, "%s.%s", prefix, e -> name);
+		else
+			0 == asprintf(&symname, "%s.____%d", prefix, *coff);
+		
+		// register the symbol
+		te1 = lw_expr_build(lw_expr_type_int, *coff);
+		te2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, te1, l -> addr);
+		register_symbol(as, l, symname, te2, symbol_flag_nocheck);
+		lw_expr_destroy(te2);
+		lw_expr_destroy(te1);
+		
+		if (e -> substruct)
+		{
+			char *t;
+			0 == asprintf(&t, "sizeof{%s}", symname);
+			te1 = lw_expr_build(lw_expr_type_int, e -> substruct -> size);
+			register_symbol(as, l, t, te1, symbol_flag_nocheck);
+			lw_expr_destroy(te1);
+			lw_free(t);
+			pseudo_endstruct_aux(as, l, e -> substruct -> fields, symname, coff);
+		}
+		else
+		{
+			*coff += e -> size;
+		}
+		e = e -> next;
+	}
+}
+
+
+PARSEFUNC(pseudo_parse_endstruct)
+{
+	char *t;
+	int coff = 0;
+	lw_expr_t te;
+	
+	if (as -> instruct == 0)
+	{
+		lwasm_register_warning(as, l, "endstruct without struct");
+		skip_operand(p);
+		return;
+	}
+	
+	0 == asprintf(&t, "sizeof{%s}", as -> cstruct -> name);
+	te = lw_expr_build(lw_expr_type_int, as -> cstruct -> size);
+	register_symbol(as, l, t, te, symbol_flag_nocheck);
+	lw_expr_destroy(te);
+	lw_free(t);
+	
+	l -> soff = as -> cstruct -> size;
+	as -> instruct = 0;
+	
+	skip_operand(p);
+	
+	pseudo_endstruct_aux(as, l, as -> cstruct -> fields, as -> cstruct -> name, &coff);
+	
+	l -> len = 0;
+}
+
+void register_struct_entry(asmstate_t *as, line_t *l, int size, structtab_t *ss)
+{
+	structtab_field_t *e, *e2;
+	
+	l -> soff = as -> cstruct -> size;
+	e = lw_alloc(sizeof(structtab_field_t));
+	e -> next = NULL;
+	e -> size = size;
+	if (l -> sym)
+		e -> name = lw_strdup(l -> sym);
+	else
+		e -> name = NULL;
+	e -> substruct = ss;
+	if (as -> cstruct -> fields)
+	{
+		for (e2 = as -> cstruct -> fields; e2 -> next; e2 = e2 -> next)
+			/* do nothing */ ;
+		e2 -> next = e;
+	}
+	else
+	{
+		as -> cstruct -> fields = e;
+	}
+	as -> cstruct -> size += size;
+}
+
+int expand_struct(asmstate_t *as, line_t *l, char **p, char *opc)
+{
+	structtab_t *s;
+	char *t;
+	lw_expr_t te;
+	int addr = 0;
+
+	debug_message(as, 200, "Checking for structure expansion: %s", opc);
+
+	for (s = as -> structs; s; s = s -> next)
+	{
+		if (!strcmp(opc, s -> name))
+			break;
+	}
+	
+	if (!s)
+		return -1;
+	
+	debug_message(as, 10, "Expanding structure: %s", opc);
+	
+	if (!(l -> sym))
+	{
+		lwasm_register_error(as, l, "Cannot declare a structure without a symbol name.");
+		return;
+	}
+	
+	l -> len = s -> size;
+
+	if (as -> instruct)
+		0 == asprintf(&t, "sizeof(%s.%s}", as -> cstruct -> name, l -> sym);
+	else
+		0 == asprintf(&t, "sizeof{%s}", l -> sym);
+	te = lw_expr_build(lw_expr_type_int, s -> size);
+	register_symbol(as, l, t, te, symbol_flag_nocheck);
+	lw_expr_destroy(te);
+	lw_free(t);
+	
+	if (as -> instruct)
+		0 == asprintf(&t, "%s.%s", as -> cstruct -> name, l -> sym);
+	else
+		t = lw_strdup(l -> sym);
+	pseudo_endstruct_aux(as, l, s -> fields, t, &addr);
+	lw_free(t);
+	l -> symset = 1;
+	if (as -> instruct)
+		register_struct_entry(as, l, s -> size, s);
+	return 0;
+}
+
--- a/lwasm/symbol.c	Wed Jul 14 20:17:57 2010 -0600
+++ b/lwasm/symbol.c	Wed Jul 14 22:33:55 2010 -0600
@@ -38,16 +38,19 @@
 	int version = -1;
 	char *cp;
 
-	if (*sym < 0x80 && !strchr(SSYMCHARS, *sym))
+	if (!(flags & symbol_flag_nocheck))
 	{
-		lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
-		return NULL;
-	}
+		if (*sym < 0x80 && !strchr(SSYMCHARS, *sym))
+		{
+			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+			return NULL;
+		}
 
-	if ((*sym == '$' || *sym == '@') && (sym[1] >= '0' && sym[1] <= '9'))
-	{
-		lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
-		return NULL;
+		if ((*sym == '$' || *sym == '@') && (sym[1] >= '0' && sym[1] <= '9'))
+		{
+			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+			return NULL;
+		}
 	}
 
 	for (cp = sym; *cp; cp++)
@@ -58,7 +61,7 @@
 			islocal = 1;
 		
 		// bad symbol
-		if (*cp < 0x80 && !strchr(SYMCHARS, *cp))
+		if (!(flags & symbol_flag_nocheck) && *cp < 0x80 && !strchr(SYMCHARS, *cp))
 		{
 			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
 			return NULL;
@@ -84,6 +87,7 @@
 			break;
 		}
 	}
+
 	if (se)
 	{
 		// multiply defined symbol