summaryrefslogtreecommitdiff
path: root/tools/spasm/eval.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /tools/spasm/eval.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'tools/spasm/eval.c')
-rw-r--r--tools/spasm/eval.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/tools/spasm/eval.c b/tools/spasm/eval.c
new file mode 100644
index 0000000..01f8f66
--- /dev/null
+++ b/tools/spasm/eval.c
@@ -0,0 +1,130 @@
+#include "spasm.h"
+
+/**
+ * Expressions in SPASM are implemented in a totally broken manner.
+ *
+ * The result of an expression is the value of its initial argument
+ * after executing the operation of the last operand with the last argument.
+ *
+ * For example dw $cafeba00+2+4 is not equal to dw $cafeba06
+ * but to dw $cafeba04.
+ * Likewise, dw $2+$cafeba00+4 is not equal to dw $cafeba06
+ * but to dw $6 !
+ */
+
+unsigned int spasm_eval(char *expr)
+{
+ char *cset = "+-><&|*!";
+ char *csetp;
+ char *cp;
+ int ok;
+ int t = T_INTEGER;
+ char sbuf[128];
+
+ if(strcmp(expr, "*") == 0) // Return current return address
+ return curPc;
+
+ if(strcasecmp(curIns, "incbin") == 0)
+ return 0; // If current instruction is incbin, do not evaluate.
+
+ if(*expr == '"' || *expr == '\'')
+ return 0; // I won't even try to evaluate strings!
+
+ int ispan = strcspn(expr, cset);
+
+ csetp = cset;
+
+ ok = 0; // ok will be 0 if we found no operator, 1 if we found it
+
+ char op = '?';
+
+ cp = NULL;
+
+ while(*csetp)
+ {
+ char *tcp = strrchr(expr, *csetp);
+
+ if(tcp) // Found operator
+ {
+ if(tcp > cp)
+ cp = tcp;
+
+ if(*cp == '>')
+ {
+ if(*(cp-1) != '>')
+ instruction_error("Bad operator");
+ }
+
+ if(*cp == '<')
+ {
+ if(*(cp-1) != '<')
+ instruction_error("Bad operator");
+ }
+
+ cp++;
+ ok = 1;
+ op = *csetp;
+ break;
+ }
+
+ csetp++;
+ }
+
+ unsigned int one = 0;
+ unsigned int two = 0;
+
+ memcpy(sbuf, expr, ispan);
+ sbuf[ispan] = '\0';
+
+ if(strlen(sbuf) == 0)
+ strcpy(sbuf, "0");
+ //instruction_error("Bad expression");
+
+ //printf("sbuf = %s\n", sbuf);
+ one = asm_atoi(sbuf);
+
+ t = atoiT[insArgc];
+
+ if(ok)
+ {
+ strcpy(sbuf, cp);
+
+ if(strlen(sbuf) == 0)
+ instruction_error("Bad expression");
+
+ two = asm_atoi(sbuf);
+
+ if(t == T_INTEGER)
+ t = atoiT[insArgc];
+ }
+
+ atoiT[insArgc] = t;
+
+ switch(op)
+ {
+ case '+':
+ return one + two;
+ break;
+ case '-':
+ return one - two;
+ break;
+ case '<':
+ return one << two;
+ break;
+ case '>':
+ return one >> two;
+ break;
+ case '&':
+ return one & two;
+ break;
+ case '|':
+ case '!':
+ return one | two;
+ break;
+ case '*':
+ return one * two;
+ break;
+ }
+
+ return one;
+}