diff lwasm/lwasm.c @ 346:a82c55070624

Added expression parsing infrastructure and misc fixes
author lost@starbug
date Sat, 27 Mar 2010 19:04:03 -0600
parents 7416c3f9c321
children 1649bc7bda5a
line wrap: on
line diff
--- a/lwasm/lwasm.c	Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/lwasm.c	Sat Mar 27 19:04:03 2010 -0600
@@ -25,6 +25,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <string.h>
 
 #include <lw_expr.h>
 #include <lw_alloc.h>
@@ -32,12 +33,12 @@
 
 #include "lwasm.h"
 
-lw_expr_t lwasm_evaluate_var(char *var)
+lw_expr_t lwasm_evaluate_var(char *var, void *priv)
 {
 	return NULL;
 }
 
-lw_expr_t lwasm_evaluate_special(int t, void *ptr)
+lw_expr_t lwasm_evaluate_special(int t, void *ptr, void *priv)
 {
 	switch (t)
 	{
@@ -49,6 +50,15 @@
 			return lw_expr_build(lw_expr_type_int, cl -> len);
 		}
 		break;
+		
+	case lwasm_expr_lineaddr:
+		{
+			line_t *cl = ptr;
+			if (cl -> addr)
+				return lw_expr_copy(cl -> addr);
+			else
+				return NULL;
+		}
 	}
 	return NULL;
 }
@@ -85,3 +95,339 @@
 	as -> nextcontext++;
 	return r;
 }
+
+void lwasm_emit(line_t *cl, int byte)
+{
+	if (cl -> outputl == cl -> outputbl)
+	{
+		cl -> output = lw_realloc(cl -> output, cl -> outputbl + 8);
+		cl -> outputbl += 8;
+	}
+	cl -> output[cl -> outputl++] = byte & 0xff;
+}
+
+void lwasm_emitop(line_t *cl, int opc)
+{
+	if (opc > 0x100)
+		lwasm_emit(cl, opc >> 8);
+	lwasm_emit(cl, opc);
+}
+
+lw_expr_t lwasm_parse_term(char **p, void *priv)
+{
+	asmstate_t *as = priv;
+	int val;
+	
+	if (!**p)
+		return NULL;
+	
+	if (**p == '*' || (
+			**p == '.'
+			&& !((*p)[1] >= 'A' && (*p)[1] <= 'Z')
+			&& !((*p)[1] >= 'a' && (*p)[1] <= 'z')
+			&& !((*p)[1] >= '0' && (*p)[1] <= '9')
+		))
+	{
+		// special "symbol" for current line addr (*, .)
+		(*p)++;
+		return lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, as -> cl);
+	}
+	
+	// branch points
+	if (**p == '<')
+	{
+		(*p)++;
+		return lw_expr_build(lw_expr_type_special, lwasm_expr_prevbp, as -> cl);
+	}
+	if (**p == '>')
+	{
+		(*p)++;
+		return lw_expr_build(lw_expr_type_special, lwasm_expr_nextbp, as -> cl);
+	}
+	
+	// double ascii constant
+	if (**p == '"')
+	{
+		int v;
+		(*p)++;
+		if (!**p)
+			return NULL;
+		if (!*((*p)+1))
+			return NULL;
+		v = (unsigned char)**p << 8 | (unsigned char)*((*p)+1);
+		(*p) += 2;
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+	
+	if (**p == '\'')
+	{
+		int v;
+		
+		(*p)++;
+		if (!**p)
+			return NULL;
+		
+		v = (unsigned char)**p;
+		(*p)++;
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+	
+	if (**p == '&')
+	{
+		// decimal constant
+		int v = 0;
+		(*p)++;
+
+		if (!strchr("0123456789", **p))
+			return NULL;
+
+		while (**p && strchr("0123456789", **p))
+		{
+			val = val * 10 + (**p - '0');
+			(*p)++;
+		}
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+
+	if (**p == '%')
+	{
+		// binary constant
+		int v = 0;
+		(*p)++;
+
+		if (**p != '0' && **p != '1')
+			return NULL;
+
+		while (**p && (**p == '0' || **p == '1'))
+		{
+			val = val * 2 + (**p - '0');
+			(*p)++;
+		}
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+	
+	if (**p == '$')
+	{
+		// hexadecimal constant
+		int v = 0, v2;
+		(*p)++;
+
+		if (!strchr("0123456789abcdefABCDEF", **p))
+			return NULL;
+
+		while (**p && strchr("0123456789abcdefABCDEF", **p))
+		{
+			v2 = toupper(**p) - '0';
+			if (v2 > 9)
+				v2 -= 7;
+			val = val * 16 + v2;
+			(*p)++;
+		}
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+	
+	if (**p == '0' && (*((*p)+1) == 'x' || *((*p)+1) == 'X'))
+	{
+		// hexadecimal constant, C style
+		int v = 0, v2;
+		(*p)+=2;
+
+		if (!strchr("0123456789abcdefABCDEF", **p))
+			return NULL;
+
+		while (**p && strchr("0123456789abcdefABCDEF", **p))
+		{
+			v2 = toupper(**p) - '0';
+			if (v2 > 9)
+				v2 -= 7;
+			val = val * 16 + v2;
+			(*p)++;
+		}
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+	
+	if (**p == '@' && (*((*p)+1) >= '0' && *((*p)+1) <= '7'))
+	{
+		// octal constant
+		int v = 0;
+		(*p)++;
+
+		if (!strchr("01234567", **p))
+			return NULL;
+
+		while (**p && strchr("01234567", **p))
+		{
+			val = val * 8 + (**p - '0');
+			(*p)++;
+		}
+		return lw_expr_build(lw_expr_type_int, v);
+	}
+	
+
+	// symbol or bare decimal or suffix constant here
+	do
+	{
+		int havedol = 0;
+		int l = 0;
+		
+		while ((*p)[l] && strchr(SYMCHARS, (*p)[l]))
+		{
+			if ((*p)[l] == '$')
+				havedol = 1;
+			l++;
+		}
+		if (l == 0)
+			return NULL;
+		
+		if (havedol || **p < '0' || **p > '9')
+		{
+			// have a symbol here
+			char *sym;
+			lw_expr_t term;
+			
+			sym = lw_strndup(*p, l);
+			(*p) += l;
+			term = lw_expr_build(lw_expr_type_var, sym);
+			lw_free(sym);
+			return term;
+		}
+	} while (0);
+	
+	if (!**p)
+		return NULL;
+	
+	// we have a numeric constant here, either decimal or postfix base notation
+	{
+		int decval = 0, binval = 0, hexval = 0, octval = 0;
+		int valtype = 15; // 1 = bin, 2 = oct, 4 = dec, 8 = hex
+		int bindone = 0;
+		int val;
+		int dval;
+		
+		while (1)
+		{
+			if (!**p || !strchr("0123456789ABCDEFabcdefqhoQHO", **p))
+			{
+				// we can legally be bin or decimal here
+				if (bindone)
+				{
+					// just finished a binary value
+					val = binval;
+					break;
+				}
+				else if (valtype & 4)
+				{
+					val = decval;
+					break;
+				}
+				else
+				{
+					// bad value
+					return NULL;
+				}
+			}
+			
+			dval = toupper(**p);
+			(*p)++;
+			
+			if (bindone)
+			{
+				// any characters past "B" means it is not binary
+				bindone = 0;
+				valtype &= 14;
+			}
+			
+			switch (dval)
+			{
+			case 'Q':
+			case 'O':
+				if (valtype & 2)
+				{
+					val = octval;
+					valtype = -1;
+					break;
+				}
+				else
+				{
+					return NULL;
+				}
+				/* can't get here */
+			
+			case 'H':
+				if (valtype & 8)
+				{
+					val = hexval;
+					valtype = -1;
+					break;
+				}
+				else
+				{
+					return NULL;
+				}
+				/* can't get here */
+			
+			case 'B':
+				// this is a bit of a sticky one since B may be a
+				// hex number instead of the end of a binary number
+				// so it falls through to the digit case
+				if (valtype & 1)
+				{
+					// could still be binary of hex
+					bindone = 1;
+					valtype = 9;
+				}
+				/* fall through intented */
+			
+			default:
+				// digit
+				dval -= '0';
+				if (dval > 9)
+					dval -= 7;
+				if (valtype & 8)
+					hexval = hexval * 16 + dval;
+				if (valtype & 4)
+				{
+					if (dval > 9)
+						valtype &= 11;
+					else
+						decval = decval * 10 + dval;
+				}
+				if (valtype & 2)
+				{
+					if (dval > 7)
+						valtype &= 13;
+					else
+						octval = octval * 8 + dval;
+				}
+				if (valtype & 1)
+				{
+					if (dval > 1)
+						valtype &= 14;
+					else
+						binval = binval * 2 + dval;
+				}
+			}
+			if (valtype == -1)
+				break;
+			
+			// return if no more valid types
+			if (valtype == 0)
+				return NULL;
+			
+			val = decval; // in case we fall through	
+		} 
+		
+		// get here if we have a value
+		return lw_expr_build(lw_expr_type_int, val);
+	}
+	// can't get here
+}
+
+lw_expr_t lwasm_parse_expr(asmstate_t *as, char **p)
+{
+	lw_expr_t e;
+	
+	e = lw_expr_parse(p, as);
+	
+	return e;
+}