# 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___ */