521f787e9fe39897b4bfe5d7797fc79b3aabd7cd
[rmac] / parmode.h
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // PARMODE.C - Addressing Modes Parser Include
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 // This file is included (twice) to parse two addressing modes, into slightly
10 // different var names
11 {
12         // Dn
13         // An
14         // # expression
15         if ((*tok >= KW_D0) && (*tok <= KW_D7))
16         {
17                 AMn = DREG;
18                 AnREG = *tok++ & 7;
19         }
20         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
21         {
22                 AMn = AREG;
23                 AnREG = *tok++ & 7;
24         }
25         else if (*tok == '#')
26         {
27                 tok++;
28
29                 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
30                         return ERROR;
31
32                 AMn = IMMED;
33         }
34
35         // Small problem with this is that the opening parentheses might be an
36         // expression that's part of a displacement; this code will falsely flag
37         // that as an error.
38
39         // (An)
40         // (An)+
41         // (An,Xn[.siz][*scale])
42         // (PC,Xn[.siz][*scale])
43         // (d16,An)
44         // (d8,An,Xn[.siz][*scale])
45         // (d16,PC)
46         // (d8,PC,Xn[.siz][*scale])
47         // ([bd,An],Xn,od)
48         // ([bd,An,Xn],od)
49         // ([bd,PC],Xn,od)
50         // ([bd,PC,Xn],od)
51         else if (*tok == '(')
52         {
53                 tok++;
54
55                 if ((*tok >= KW_A0) && (*tok <= KW_A7))
56                 {
57                         AnREG = *tok++ & 7;
58
59                         if (*tok == ')')
60                         {
61                                 tok++;
62
63                                 if (*tok == '+')
64                                 {
65                                         tok++;
66                                         AMn = APOSTINC;
67                                 }
68                                 else
69                                         AMn = AIND;
70
71                                 goto AnOK;
72                         }
73
74                         AMn = AINDEXED;
75                         goto AMn_IX0;            // Handle ",Xn[.siz][*scale])"
76                 }
77                 else if (*tok == KW_PC)
78                 {                            // (PC,Xn[.siz][*scale]) 
79                         tok++;
80                         AMn = PCINDEXED;
81
82                         // Common index handler; enter here with 'tok' pointing at the
83                         // comma.
84
85                         AMn_IX0:                 // Handle indexed with missing expr
86
87                         AnEXVAL = 0;
88                         AnEXATTR = ABS | DEFINED;
89
90                         AMn_IXN:                 // Handle any indexed (tok -> a comma)
91
92                         if (*tok++ != ',')
93                                 goto badmode;
94
95                         if (*tok < KW_D0 || *tok > KW_A7)
96                                 goto badmode;
97
98                         AnIXREG = *tok++ & 15;
99
100                         switch ((int)*tok)
101                         {                        // Index reg size: <empty> | .W | .L 
102                         case DOTW:
103                                 tok++;
104                         default:
105                                 AnIXSIZ = 0;
106                                 break;
107                         case DOTL:
108                                 AnIXSIZ = 0x0800;
109                                 tok++;
110                                 break;
111                         case DOTB:               // .B not allowed here...
112                                 goto badmode;
113                         }
114
115                         if (*tok == '*')
116                         {                        // scale: *1, *2, *4, *8 
117                                 tok++;
118
119                                 if (*tok++ != CONST || *tok > 8)
120                                         goto badmode;
121
122                                 switch ((int)*tok++)
123                                 {
124                                 case 1:
125                                         break;
126                                 case 2:
127                                         AnIXSIZ |= TIMES2;
128                                         break;
129                                 case 4:
130                                         AnIXSIZ |= TIMES4;
131                                         break;
132                                 case 8:
133                                         AnIXSIZ |= TIMES8;
134                                         break;
135                                 default:
136                                         goto badmode;
137                                 }
138                         }
139
140                         if (*tok++ != ')')         // final ")" 
141                                 goto badmode;
142
143                         goto AnOK;
144                 }
145                 else if (*tok == '[')
146                 {                              // ([... 
147                         goto unmode;
148                 }
149                 else
150                 {                              // (expr... 
151                         if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
152                                 return ERROR;
153
154                         // It could be that this is really just an expression prefixing a
155                         // register as a displacement...
156                         if (*tok == ')')
157                         {
158                                 tok++;
159                                 goto CHK_FOR_DISPn;
160                         }
161
162                         // Otherwise, check for PC & etc displacements...
163                         if (*tok++ != ',')
164                                 goto badmode;
165
166                         if ((*tok >= KW_A0) && (*tok <= KW_A7))
167                         {
168                                 AnREG = *tok & 7;
169                                 tok++;
170
171                                 if (*tok == ',')
172                                 {
173                                         AMn = AINDEXED;
174                                         goto AMn_IXN;
175                                 }
176                                 else if (*tok == ')')
177                                 {
178                                         AMn = ADISP;
179                                         tok++;
180                                         goto AnOK;
181                                 }
182                                 else
183                                         goto badmode;
184                         }
185                         else if (*tok == KW_PC)
186                         {
187                                 if (*++tok == ',')
188                                 {                             // expr(PC,Xn...)
189                                         AMn = PCINDEXED;
190                                         goto AMn_IXN;
191                                 }
192                                 else if (*tok == ')')
193                                 {
194                                         AMn = PCDISP;             // expr(PC) 
195                                         tok++;
196                                         goto AnOK;
197                                 }
198                                 else
199                                         goto badmode;
200                         }
201                         else
202                                 goto badmode;
203                 }
204         }
205         else if (*tok == '-' && tok[1] == '(' && ((tok[2] >= KW_A0) && (tok[2] <= KW_A7)) && tok[3] == ')')
206         {
207                 AMn = APREDEC;
208                 AnREG = tok[2] & 7;
209                 tok += 4;
210         }
211         else if (*tok == KW_CCR)
212         {
213                 AMn = AM_CCR;
214                 tok++;
215                 goto AnOK;
216         }
217         else if (*tok == KW_SR)
218         {
219                 AMn = AM_SR;
220                 tok++;
221                 goto AnOK;
222         }
223         else if (*tok == KW_USP)
224         {
225                 AMn = AM_USP;
226                 tok++;
227                 goto AnOK;
228         }
229         // expr
230         // expr.w
231         // expr.l
232         // d16(An)
233         // d8(An,Xn[.siz])
234         // d16(PC)
235         // d8(PC,Xn[.siz])
236         else
237         {
238                 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
239                         return ERROR;
240
241 CHK_FOR_DISPn:
242                 if (*tok == DOTW)
243                 {
244                         // expr.W 
245                         tok++;
246                         AMn = ABSW;
247
248                         if ((AnEXATTR & (TDB|DEFINED)) == DEFINED && (AnEXVAL < 0x10000))
249                                 AnEXVAL = (int32_t)(int16_t)AnEXVAL;  // Sign extend value
250
251                         goto AnOK;
252                 }
253                 else if (*tok != '(')
254                 {
255                         // expr[.L]
256                         AMn = ABSL;
257
258                         // Defined, absolute values from $FFFF8000..$00007FFF get optimized
259                         // to absolute short
260                         if (optim_flag && (AnEXATTR & (TDB|DEFINED)) == DEFINED && (AnEXVAL + 0x8000) < 0x10000)
261                         {
262                                 AMn = ABSW;
263
264                                 if (sbra_flag)
265                                         warn("absolute value from $FFFF8000..$00007FFF optimised to absolute short");
266                         }
267
268                         // Is .L forced here?
269                         if (*tok == DOTL)
270                         {
271                                 tok++;
272                                 AMn = ABSL;
273                         }
274
275                         goto AnOK;
276                 }
277
278                 tok++;
279
280                 if ((*tok >= KW_A0) && (*tok <= KW_A7))
281                 {
282                         AnREG = *tok++ & 7;
283
284                         if (*tok == ')')
285                         {
286                                 AMn = ADISP;
287                                 tok++;
288                                 goto AnOK;
289                         }
290
291                         AMn = AINDEXED;
292                         goto AMn_IXN;
293                 }
294                 else if (*tok == KW_PC)
295                 {
296                         if (*++tok == ')')
297                         {
298                                 AMn = PCDISP;
299                                 tok++;
300                                 goto AnOK;
301                         }
302
303                         AMn = PCINDEXED;
304                         goto AMn_IXN;
305                 }
306                 goto badmode;
307         }
308
309         // Addressing mode OK
310
311         AnOK:
312         ;
313 }
314
315 // Clean up dirty little macros
316 #undef AnOK
317 #undef AMn
318 #undef AnREG
319 #undef AnIXREG
320 #undef AnIXSIZ
321 #undef AnEXPR
322 #undef AnEXVAL
323 #undef AnEXATTR
324 #undef AnOEXPR
325 #undef AnOEXVAL
326 #undef AnOEXATTR
327 #undef AnESYM
328 #undef AMn_IX0
329 #undef AMn_IXN
330 #undef CHK_FOR_DISPn