# HG changeset patch
# User lost@starbug
# Date 1269738243 21600
# Node ID a82c55070624e451346f0a46121e592718861160
# Parent 7416c3f9c321aba3160f451982203cff15eb52b6
Added expression parsing infrastructure and misc fixes
diff -r 7416c3f9c321 -r a82c55070624 TODO
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TODO Sat Mar 27 19:04:03 2010 -0600
@@ -0,0 +1,1 @@
+[LWASM] Bring macro scheme up to date to use lwlib structures
diff -r 7416c3f9c321 -r a82c55070624 lwasm/Makefile.am
--- a/lwasm/Makefile.am Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/Makefile.am Sat Mar 27 19:04:03 2010 -0600
@@ -1,5 +1,5 @@
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib -I$(top_builddir)/lwlib -I$(top_srcdir)/lwlib
bin_PROGRAMS = lwasm
-lwasm_SOURCES = main.c pragma.c input.c pass1.c lwasm.c instab.c symbol.c macro.c
+lwasm_SOURCES = main.c pragma.c input.c pass1.c lwasm.c instab.c symbol.c macro.c insn_inh.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
diff -r 7416c3f9c321 -r a82c55070624 lwasm/insn_inh.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_inh.c Sat Mar 27 19:04:03 2010 -0600
@@ -0,0 +1,35 @@
+/*
+insn_inh.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 .
+
+*/
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(insn_parse_inh)
+{
+ l -> len = OPLEN(instab[l -> insn].ops[0]);
+}
+
+RESOLVEFUNC(insn_resolve_inh)
+{
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+}
diff -r 7416c3f9c321 -r a82c55070624 lwasm/instab.c
--- a/lwasm/instab.c Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/instab.c Sat Mar 27 19:04:03 2010 -0600
@@ -26,11 +26,19 @@
#define __instab_c_seen__
#include "instab.h"
-// don't need to parse anything for inh
-// so it can just be NULL
-#define insn_parse_inh NULL
+// inherent
+extern PARSEFUNC(insn_parse_inh);
+extern RESOLVEFUNC(insn_resolve_inh);
-extern RESOLVEFUNC(insn_resolve_inh);
+// MACRO pseudo op
+extern PARSEFUNC(pseudo_parse_macro);
+#define pseudo_resolve_macro NULL
+
+// ENDM pseudo op
+extern PARSEFUNC(pseudo_parse_endm);
+#define pseudo_resolve_endm NULL
+
+
extern PARSEFUNC(insn_parse_gen8);
extern RESOLVEFUNC(insn_resolve_gen8);
extern PARSEFUNC(insn_parse_gen16);
@@ -116,10 +124,6 @@
extern RESOLVEFUNC(pseudo_resolve_else);
extern PARSEFUNC(pseudo_parse_endc);
extern RESOLVEFUNC(pseudo_resolve_endc);
-extern PARSEFUNC(pseudo_parse_macro);
-extern RESOLVEFUNC(pseudo_resolve_macro);
-extern PARSEFUNC(pseudo_parse_endm);
-extern RESOLVEFUNC(pseudo_resolve_endm);
extern PARSEFUNC(pseudo_parse_setdp);
extern RESOLVEFUNC(pseudo_resolve_setdp);
extern PARSEFUNC(pseudo_parse_set);
@@ -321,8 +325,9 @@
{ "nega", { 0x40, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, lwasm_insn_normal},
{ "negb", { 0x50, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, lwasm_insn_normal},
{ "negd", { 0x1040, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, lwasm_insn_is6309},
+*/
{ "nop", { 0x12, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, lwasm_insn_normal},
-
+/*
{ "oim", { 0x01, 0x61, 0x71, -1 }, insn_parse_logicmem, insn_resolve_logicmem, lwasm_insn_is6309},
{ "ora", { 0x9a, 0xaa, 0xba, 0x8a}, insn_parse_gen8, insn_resolve_gen8, lwasm_insn_normal},
{ "orb", { 0xda, 0xea, 0xfa, 0xca}, insn_parse_gen8, insn_resolve_gen8, lwasm_insn_normal},
@@ -463,9 +468,10 @@
{ "ifdef", { -1, -1, -1, -1}, pseudo_parse_ifdef, pseudo_resolve_ifdef, lwasm_insn_cond},
{ "ifndef", { -1, -1, -1, -1}, pseudo_parse_ifndef, pseudo_resolve_ifndef, lwasm_insn_cond},
+*/
{ "macro", { -1, -1, -1, -1}, pseudo_parse_macro, pseudo_resolve_macro, lwasm_insn_cond | lwasm_insn_setsym},
{ "endm", { -1, -1, -1, -1}, pseudo_parse_endm, pseudo_resolve_endm, lwasm_insn_cond | lwasm_insn_setsym | lwasm_insn_endm},
-
+/*
{ "setdp", { -1, -1, -1, -1}, pseudo_parse_setdp, pseudo_resolve_setdp, lwasm_insn_normal},
{ "set", { -1, -1, -1, -1}, pseudo_parse_set, pseudo_resolve_set, lwasm_insn_setsym},
diff -r 7416c3f9c321 -r a82c55070624 lwasm/lwasm.c
--- 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
#include
+#include
#include
#include
@@ -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;
+}
diff -r 7416c3f9c321 -r a82c55070624 lwasm/lwasm.h
--- a/lwasm/lwasm.h Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/lwasm.h Sat Mar 27 19:04:03 2010 -0600
@@ -26,9 +26,20 @@
#include
#include
+
+// these are allowed chars BELOW 0x80 for symbols
+// first is symbol start chars, second is anywhere in symbol
+#define SSYMCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_@$"
+#define SYMCHARS SSYMCHARS ".?0123456789"
+
+typedef struct asmstate_s asmstate_t;
+
enum
{
- lwasm_expr_linelen = 1
+ lwasm_expr_linelen = 1, // length of ref'd line
+ lwasm_expr_lineaddr = 2, // addr of ref'd line
+ lwasm_expr_nextbp = 3, // next branch point
+ lwasm_expr_prevbp = 4 // previous branch point
};
enum lwasm_output_e
@@ -78,9 +89,13 @@
int insn; // number of insn in insn table
int symset; // set if the line symbol was consumed by the instruction
char *sym; // symbol, if any, on the line
+ unsigned char *output; // output bytes
+ int outputl; // size of output
+ int outputbl; // size of output buffer
lwasm_error_t *err; // list of errors
line_t *prev; // previous line
line_t *next; // next line
+ asmstate_t *as; // assembler state data ptr
};
enum
@@ -113,7 +128,7 @@
macrotab_t *next; // next macro in list
};
-typedef struct
+struct asmstate_s
{
int output_format; // output format
int target; // assembly target
@@ -127,6 +142,8 @@
line_t *line_head; // start of lines list
line_t *line_tail; // tail of lines list
+
+ line_t *cl; // current line pointer
int context; // the current "context"
int nextcontext; // the next available context
@@ -140,7 +157,7 @@
void *input_data; // opaque data used by the input system
lw_stringlist_t include_list; // include paths
lw_stack_t file_dir; // stack of the "current file" dir
-} asmstate_t;
+};
#ifndef ___symbol_c_seen___
@@ -153,8 +170,11 @@
extern void lwasm_register_error(asmstate_t *as, line_t *cl, const char *msg, ...);
extern int lwasm_next_context(asmstate_t *as);
+extern void lwasm_emit(line_t *cl, int byte);
+extern void lwasm_emitop(line_t *cl, int opc);
#endif
+#define OPLEN(op) (((op)>0xFF)?2:1)
#endif /* ___lwasm_h_seen___ */
diff -r 7416c3f9c321 -r a82c55070624 lwasm/macro.c
--- a/lwasm/macro.c Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/macro.c Sat Mar 27 19:04:03 2010 -0600
@@ -34,10 +34,12 @@
#include "input.h"
#include "instab.h"
-PARSEFUNC(pseudo_macro_parse)
+PARSEFUNC(pseudo_parse_macro)
{
macrotab_t *m;
+ l -> len = 0;
+
if (as -> skipcond)
{
as -> skipmacro = 1;
@@ -80,8 +82,10 @@
as -> inmacro = 1;
}
-PARSEFUNC(pseudo_endm_parse)
+PARSEFUNC(pseudo_parse_endm)
{
+ l -> len = 0;
+
if (as -> skipcond)
{
as -> skipmacro = 0;
diff -r 7416c3f9c321 -r a82c55070624 lwasm/main.c
--- a/lwasm/main.c Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/main.c Sat Mar 27 19:04:03 2010 -0600
@@ -165,9 +165,9 @@
assembler on the first file
*/
extern void do_pass1(asmstate_t *as);
-extern lw_expr_t lwasm_evaluate_special(int t, void *ptr);
-extern lw_expr_t lwasm_evaluate_var(char *var);
-
+extern lw_expr_t lwasm_evaluate_special(int t, void *ptr, void *priv);
+extern lw_expr_t lwasm_evaluate_var(char *var, void *priv);
+extern lw_expr_t lwasm_parse_term(char **p, void *priv);
int main(int argc, char **argv)
{
/* assembler state */
diff -r 7416c3f9c321 -r a82c55070624 lwasm/pass1.c
--- a/lwasm/pass1.c Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/pass1.c Sat Mar 27 19:04:03 2010 -0600
@@ -22,6 +22,7 @@
#include
#include
+#include
#include
#include
@@ -78,11 +79,10 @@
printf("%s\n", line);
cl = lw_alloc(sizeof(line_t));
- cl -> next = NULL;
+ memset(cl, 0, sizeof(line_t));
cl -> prev = as -> line_tail;
- cl -> len = -1;
cl -> insn = -1;
- cl -> err = NULL;
+ cl -> as = as;
if (!as -> line_tail)
{
as -> line_head = cl;
@@ -95,9 +95,10 @@
te = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, cl -> prev);
cl -> addr = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, cl -> prev -> addr, te);
lw_expr_destroy(te);
- lw_expr_simplify(cl -> addr);
+ lw_expr_simplify(cl -> addr, as);
}
as -> line_tail = cl;
+ as -> cl = cl;
// blank lines don't count for anything
// except a local symbol context break
@@ -222,6 +223,7 @@
// no parse func means operand doesn't matter
if (instab[opnum].parse)
{
+ cl -> len = -1;
// call parse function
(instab[opnum].parse)(as, cl, &p1);
diff -r 7416c3f9c321 -r a82c55070624 lwasm/symbol.c
--- a/lwasm/symbol.c Thu Mar 25 23:17:54 2010 -0600
+++ b/lwasm/symbol.c Sat Mar 27 19:04:03 2010 -0600
@@ -29,10 +29,6 @@
#include "lwasm.h"
-// these are allowed chars BELOW 0x80
-#define SSYMCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_@$"
-#define SYMCHARS SSYMCHARS ".?0123456789"
-
struct symtabe *register_symbol(asmstate_t *as, line_t *cl, char *sym, lw_expr_t val, int flags)
{
struct symtabe *se;
diff -r 7416c3f9c321 -r a82c55070624 lwlib/lw_expr.c
--- a/lwlib/lw_expr.c Thu Mar 25 23:17:54 2010 -0600
+++ b/lwlib/lw_expr.c Sat Mar 27 19:04:03 2010 -0600
@@ -33,6 +33,12 @@
static lw_expr_fn_t *evaluate_special = NULL;
static lw_expr_fn2_t *evaluate_var = NULL;
+static lw_expr_fn3_t *parse_term = NULL;
+
+void lw_expr_set_term_parser(lw_expr_fn3_t *fn)
+{
+ parse_term = fn;
+}
void lw_expr_set_special_handler(lw_expr_fn_t *fn)
{
@@ -353,7 +359,7 @@
return 1;
}
-void lw_expr_simplify(lw_expr_t E)
+void lw_expr_simplify(lw_expr_t E, void *priv)
{
struct lw_expr_opers *o;
@@ -363,7 +369,7 @@
{
lw_expr_t te;
- te = evaluate_special(E -> value, E -> value2);
+ te = evaluate_special(E -> value, E -> value2, priv);
if (te)
{
for (o = E -> operands; o; o = o -> next)
@@ -389,7 +395,7 @@
{
lw_expr_t te;
- te = evaluate_var(E -> value2);
+ te = evaluate_var(E -> value2, priv);
if (te)
{
for (o = E -> operands; o; o = o -> next)
@@ -420,7 +426,7 @@
// simplify operands
for (o = E -> operands; o; o = o -> next)
- lw_expr_simplify(o -> p);
+ lw_expr_simplify(o -> p, priv);
for (o = E -> operands; o; o = o -> next)
{
@@ -637,3 +643,187 @@
return;
}
}
+
+/*
+
+The following two functions are co-routines which evaluate an infix
+expression. lw_expr_parse_term checks for unary prefix operators then, if
+none found, passes the string off the the defined helper function to
+determine what the term really is. It also handles parentheses.
+
+lw_expr_parse_expr evaluates actual expressions with infix operators. It
+respects the order of operations.
+
+The end of an expression is determined by the presence of any of the
+following conditions:
+
+1. a NUL character
+2. a whitespace character
+3. a )
+4. a ,
+5. any character that is not recognized as a term
+
+lw_expr_parse_term returns NULL if there is no term (end of expr, etc.)
+
+lw_expr_parse_expr returns NULL if there is no expression or on a syntax
+error.
+
+*/
+
+lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec);
+
+lw_expr_t lw_expr_parse_term(char **p, void *priv)
+{
+ lw_expr_t term, term2;
+
+eval_next:
+ if (!**p || isspace(**p) || **p == ')' || **p == ']')
+ return NULL;
+
+ // parentheses
+ if (**p == '(')
+ {
+ (*p)++;
+ term = lw_expr_parse_expr(p, priv, 0);
+ if (**p != ')')
+ {
+ lw_expr_destroy(term);
+ return NULL;
+ }
+ (*p)++;
+ return term;
+ }
+
+ // unary +
+ if (**p == '+')
+ {
+ (*p)++;
+ goto eval_next;
+ }
+
+ // unary - (prec 200)
+ if (**p == '-')
+ {
+ (*p)++;
+ term = lw_expr_parse_expr(p, priv, 200);
+ if (!term)
+ return NULL;
+
+ term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_neg, term);
+ lw_expr_destroy(term);
+ return term2;
+ }
+
+ // unary ^ or ~ (complement, prec 200)
+ if (**p == '^' || **p == '~')
+ {
+ (*p)++;
+ term = lw_expr_parse_expr(p, priv, 200);
+ if (!term)
+ return NULL;
+
+ term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_com, term);
+ lw_expr_destroy(term);
+ return term2;
+ }
+
+ // non-operator - pass to caller
+ return parse_term(p, priv);
+}
+
+lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec)
+{
+ static const struct operinfo
+ {
+ int opernum;
+ char *operstr;
+ int operprec;
+ } operators[] =
+ {
+ { lw_expr_oper_plus, "+", 100 },
+ { lw_expr_oper_minus, "-", 100 },
+ { lw_expr_oper_times, "*", 100 },
+ { lw_expr_oper_divide, "/", 150 },
+ { lw_expr_oper_mod, "%", 150 },
+ { lw_expr_oper_intdiv, "\\", 150 },
+
+ { lw_expr_oper_and, "&&", 25 },
+ { lw_expr_oper_or, "||", 25 },
+
+ { lw_expr_oper_bwand, "&", 50 },
+ { lw_expr_oper_bwor, "|", 50 },
+ { lw_expr_oper_bwxor, "^", 50 },
+
+ { lw_expr_oper_none, "", 0 }
+ };
+
+ int opern, i;
+ lw_expr_t term1, term2, term3;
+
+ if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']')
+ return NULL;
+
+ term1 = lw_expr_parse_term(p, priv);
+ if (!term1)
+ return NULL;
+
+eval_next:
+ if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']')
+ return term1;
+
+ // expecting an operator here
+ for (opern = 0; operators[opern].opernum != lw_expr_oper_none; opern++)
+ {
+ for (i = 0; (*p)[i] && operators[opern].operstr[i] && ((*p)[i] == operators[opern].operstr[i]); i++)
+ /* do nothing */;
+ if (operators[opern].operstr[i] == '\0')
+ break;
+ }
+
+ if (operators[opern].opernum == lw_expr_oper_none)
+ {
+ // unrecognized operator
+ lw_expr_destroy(term1);
+ return NULL;
+ }
+
+ // operator number is in opern, length of oper in i
+
+ // logic:
+ // if the precedence of this operation is <= to the "prec" flag,
+ // we simply return without advancing the input pointer; the operator
+ // will be evaluated again in the enclosing function call
+ if (operators[opern].operprec <= prec)
+ return term1;
+
+ // logic:
+ // we have a higher precedence operator here so we will advance the
+ // input pointer to the next term and let the expression evaluator
+ // loose on it after which time we will push our operator onto the
+ // stack and then go on with the expression evaluation
+ (*p) += i;
+
+ // evaluate next expression(s) of higher precedence
+ term2 = lw_expr_parse_expr(p, priv, operators[opern].operprec);
+ if (!term2)
+ {
+ lw_expr_destroy(term1);
+ return NULL;
+ }
+
+ // now create operator
+ term3 = lw_expr_build(lw_expr_type_oper, operators[opern].opernum, term1, term2);
+ lw_expr_destroy(term1);
+ lw_expr_destroy(term2);
+
+ // the new "expression" is the next "left operand"
+ term1 = term3;
+
+ // continue evaluating
+ goto eval_next;
+}
+
+lw_expr_t lw_expr_parse(char **p, void *priv)
+{
+ return lw_expr_parse_expr(p, priv, 0);
+}
diff -r 7416c3f9c321 -r a82c55070624 lwlib/lw_expr.h
--- a/lwlib/lw_expr.h Thu Mar 25 23:17:54 2010 -0600
+++ b/lwlib/lw_expr.h Sat Mar 27 19:04:03 2010 -0600
@@ -45,7 +45,8 @@
lw_expr_oper_and, // boolean and
lw_expr_oper_or, // boolean or
lw_expr_oper_neg, // unary negation, 2's complement
- lw_expr_oper_com // unary 1's complement
+ lw_expr_oper_com, // unary 1's complement
+ lw_expr_oper_none = 0
};
#ifdef ___lw_expr_c_seen___
@@ -66,9 +67,9 @@
struct lw_expr_opers *operands; // ptr to list of operands (for operators)
};
-typedef lw_expr_t lw_expr_fn_t(int t, void *ptr);
-typedef lw_expr_t lw_expr_fn2_t(char *var);
-
+typedef lw_expr_t lw_expr_fn_t(int t, void *ptr, void *priv);
+typedef lw_expr_t lw_expr_fn2_t(char *var, void *priv);
+typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv);
#else /* def ___lw_expr_c_seen___ */
@@ -81,13 +82,17 @@
extern lw_expr_t lw_expr_build(int exprtype, ...);
extern void lw_expr_print(lw_expr_t E);
extern int lw_expr_compare(lw_expr_t E1, lw_expr_t E2);
-extern void lw_expr_simplify(lw_expr_t E);
+extern void lw_expr_simplify(lw_expr_t E, void *priv);
-typedef lw_expr_t lw_expr_fn_t(int t, void *ptr);
-typedef lw_expr_t lw_expr_fn2_t(char *var);
+typedef lw_expr_t lw_expr_fn_t(int t, void *ptr, void *priv);
+typedef lw_expr_t lw_expr_fn2_t(char *var, void *priv);
+typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv);
extern void lw_expr_set_special_handler(lw_expr_fn_t *fn);
extern void lw_expr_set_var_handler(lw_expr_fn2_t *fn);
+extern void lw_expr_set_term_parser(lw_expr_fn3_t *fn);
+
+extern lw_expr_t lw_expr_parse(char **p, void *priv);
#endif /* def ___lw_expr_c_seen___ */