-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathz80_calc.cpp
177 lines (159 loc) · 5.21 KB
/
z80_calc.cpp
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/***
* Calculate a formula
***/
#include "z80_assembler.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
int32_t GetValue( CommandP *c );
int32_t GetExpr( CommandP *c );
int32_t GetTerm( CommandP *c );
int32_t GetCalcTerm( CommandP *c );
SymbolP ErrSymbol;
RecalcListP LastRecalc;
// Get a symbol, number or bracket
int32_t GetValue( CommandP *c ) {
int32_t value = 0;
SymbolP s;
switch ( ( *c )->typ ) {
case NUM:
value = ( *c )->val;
break;
case SYMBOL:
s = (SymbolP)( *c )->val; // Symbol ptr is in the value
value = s->val; // value of the symbol
if ( !s->defined ) { // is the symbol defined?
if ( !ErrSymbol ) // Already an undefined symbol?
ErrSymbol = s; // remember this symbol, if not
}
break;
case OPCODE:
if ( ( *c )->val == '(' ) {
( *c )++; // Skip opening bracket
value = GetCalcTerm( c );
if ( ( ( *c )->typ != OPCODE ) || ( ( *c )->val != ')' ) ) {
Error( "Closing bracket is missing" );
}
} else
default:
Error( "Illegal symbol in a formula" );
}
( *c )++; // skip value, symbol or bracket
return value;
}
// interpret a sign
int32_t GetExpr( CommandP *c ) {
int32_t value;
bool negOp = false;
bool notOp = false;
if ( ( *c )->typ == OPCODE ) {
if ( ( *c )->val == '-' ) {
( *c )++; // skip the sign
negOp = true; // negative operator detected
} else if ( ( *c )->val == '+' ) {
( *c )++; // skip the sign
} else if ( ( *c )->val == '!' ) {
( *c )++; // skip the sign
notOp = true; // NOT operator detected
}
}
value = GetValue( c );
if ( negOp ) // negative operator?
value = -value; // negate
if ( notOp ) // NOT operator?
value = !value; // invertieren
return value;
}
// multiplications, etc.
int32_t GetTerm( CommandP *c ) {
int32_t value;
bool exit = false;
value = GetExpr( c );
while ( ( ( *c )->typ == OPCODE ) && !exit ) {
switch ( ( *c )->val ) {
case '*':
( *c )++; // skip operator
value *= GetExpr( c ); // Multiply
break;
case '/':
( *c )++; // skip operator
value /= GetExpr( c ); // Divide
break;
case '%':
( *c )++; // skip operator
value %= GetExpr( c ); // Modulo
break;
case '&':
( *c )++; // skip operator
value &= GetExpr( c ); // And operator
break;
default:
exit = true;
}
}
return value;
}
// addition, etc.
int32_t GetCalcTerm( CommandP *c ) {
int32_t value;
bool exit = false;
value = GetTerm( c );
while ( ( ( *c )->typ == OPCODE ) && !exit ) {
switch ( ( *c )->val ) {
case '+':
( *c )++; // skip operator
value += GetTerm( c ); // plus
break;
case '-':
( *c )++; // skip operator
value -= GetTerm( c ); // minus
break;
case '|':
( *c )++; // skip operator
value |= GetExpr( c ); // or
break;
case '^':
( *c )++; // skip operator
value ^= GetExpr( c ); // Xor
break;
case 0x120:
( *c )++; // skip operator
value >>= GetExpr( c ); // shift to the right
break;
case 0x121:
( *c )++; // skip operator
value <<= GetExpr( c ); // shift to the left
break;
default:
exit = true;
}
}
return value;
}
// Calculate a term
int32_t CalcTerm( CommandP *c ) {
int32_t value;
CommandP cSave = *c;
CommandP cp;
int32_t len;
RecalcListP r;
LastRecalc = nullptr; // expression so far ok
ErrSymbol = nullptr; // no undefined symbol in formula
value = GetCalcTerm( c );
if ( ErrSymbol ) { // at least one symbol is undefined?
len = (long)*c - (long)cSave + sizeof( Command ); // space for the formula and end-marker
cp = (CommandP)malloc( len ); // allocate memory for the formular
if ( !cp )
exit( 1 ); // not enough memory
memset( cp, 0, len ); // erase memory
memcpy( cp, cSave, (long)*c - (long)cSave ); // transfer the formular
r = (RecalcListP)malloc( sizeof( RecalcList ) ); // allocate a recalculation list entry
r->c = cp; // link to the formula
r->typ = -1; // type: illegal (because unknown)
r->adr = 0; // address to patch = 0
r->next = ErrSymbol->recalc;
ErrSymbol->recalc = r; // link expression to symbol
LastRecalc = r; // save entry to correct the typ
}
return value;
}