summaryrefslogtreecommitdiff
path: root/tools/spasm/eval.c
blob: 01f8f66804b8f61183cf44e2d965512f50bf3265 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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;
}