comparison lwasm/macro.c @ 151:427e268e876b

renamed src to lwasm to better reflect its purpose
author lost
date Fri, 30 Jan 2009 04:01:55 +0000
parents src/macro.c@918be0c02239
children bae1e3ecdce1
comparison
equal deleted inserted replaced
150:f0881c115010 151:427e268e876b
1 /*
2 macro.c
3 Copyright © 2008 William Astle
4
5 This file is part of LWASM.
6
7 LWASM is free software: you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation, either version 3 of the License, or (at your option) any later
10 version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
17 You should have received a copy of the GNU General Public License along with
18 this program. If not, see <http://www.gnu.org/licenses/>.
19
20 Contains stuff associated with macro processing
21 */
22
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "lwasm.h"
27 #include "instab.h"
28 #include "util.h"
29
30 OPFUNC(pseudo_macro)
31 {
32 macrotab_t *m;
33
34 // if skipping a condition, flag in a macro
35 if (as -> skipcond)
36 {
37 as -> skipmacro = 1;
38 return;
39 }
40
41 // actually define a macro
42 if (as -> inmacro)
43 {
44 register_error(as, l, 1, "Attempt to define a macro inside a macro");
45 return;
46 }
47
48 as -> inmacro = 1;
49
50 // don't actually do anything if not pass 1
51 if (as -> passnum != 1)
52 return;
53
54
55 if (!l -> sym)
56 {
57 register_error(as, l, 1, "Macro definition with no effect - no symbol");
58 return;
59 }
60
61 // search for macro by same name...
62 for (m = as -> macros; m; m = m -> next)
63 {
64 if (!strcmp(m -> name, l -> sym))
65 break;
66 }
67 if (m)
68 {
69 register_error(as, l, 1, "Duplicate macro definition");
70 return;
71 }
72
73 m = lwasm_alloc(sizeof(macrotab_t));
74 m -> name = lwasm_strdup(l -> sym);
75 m -> next = as -> macros;
76 m -> lines = NULL;
77 m -> numlines = 0;
78 as -> macros = m;
79
80 while (**p && !isspace(**p))
81 (*p)++;
82 }
83
84 OPFUNC(pseudo_endm)
85 {
86 if (as -> skipcond)
87 {
88 as -> skipmacro = 0;
89 return;
90 }
91
92 if (!as -> inmacro)
93 {
94 register_error(as, l, 1, "ENDM without MACRO");
95 return;
96 }
97
98 as -> inmacro = 0;
99
100 // a macro definition counts as a context break for local symbols
101 as -> context = lwasm_next_context(as);
102 }
103
104 // the current macro will ALWAYS be the first one in the table
105 int add_macro_line(asmstate_t *as, char *optr)
106 {
107 if (!as -> inmacro)
108 return 0;
109
110 if (as -> passnum == 2)
111 return 1;
112
113 as -> macros -> lines = lwasm_realloc(as -> macros -> lines, sizeof(char *) * (as -> macros -> numlines + 1));
114 as -> macros -> lines[as -> macros -> numlines] = lwasm_strdup(optr);
115 as -> macros -> numlines += 1;
116 return 1;
117 }
118
119 void macro_add_to_buff(char **buff, int *loc, int *len, char c)
120 {
121 if (*loc == *len)
122 {
123 *buff = lwasm_realloc(*buff, *len + 32);
124 *len += 32;
125 }
126 (*buff)[(*loc)++] = c;
127 }
128
129 // this is just like a regular operation function
130 /*
131 macro args are referenced by "\n" where 1 <= n <= 9
132 or by "\{n}"; a \ can be included by writing \\
133 a comma separates argument but one can be included with "\,"
134 whitespace ends argument list but can be included with "\ " or the like
135
136 In pass 1, actually add the lines to the system, in pass 2, do not
137 In pass 2, track the number of lines to skip because they already will be
138 processed by this function - this will be in as -> skiplines
139
140 */
141 int expand_macro(asmstate_t *as, lwasm_line_t *l, char **p, char *opc)
142 {
143 int lc;
144 lwasm_line_t *cl, *nl;
145 int oldcontext;
146 macrotab_t *m;
147
148 char **args = NULL; // macro arguments
149 int nargs = 0; // number of arguments
150
151 char *p2, *p3;
152
153 int bloc, blen;
154 char *linebuff;
155
156 for (m = as -> macros; m; m = m -> next)
157 {
158 if (!strcmp(opc, m -> name))
159 break;
160 }
161 // signal no macro expansion
162 if (!m)
163 return -1;
164
165
166 // save current symbol context for after macro expansion
167 oldcontext = as -> context;
168
169 cl = l;
170
171 as -> context = lwasm_next_context(as);
172
173 // step 1: parse arguments (pass 1 only)
174 if (as -> passnum == 1)
175 {
176 while (**p && !isspace(**p) && **p != ',')
177 {
178 p2 = *p;
179 while (*p2 && !isspace(*p2) && *p2 != ',')
180 {
181 if (*p2 == '\\')
182 {
183 if (p2[1])
184 p2++;
185 }
186 p2++;
187 }
188
189 // have arg here
190 args = lwasm_realloc(args, sizeof(char *) * (nargs + 1));
191 args[nargs] = lwasm_alloc(p2 - *p + 1);
192 args[nargs][p2 - *p] = '\0';
193 memcpy(args[nargs], *p, p2 - *p);
194 *p = p2;
195
196 // now collapse out "\" characters
197 for (p3 = p2 = args[nargs]; *p2; p2++, p3++)
198 {
199 if (*p2 == '\\' && p2[1])
200 {
201 p2++;
202 }
203 *p3 = *p2;
204 }
205 *p3 = '\0';
206
207 nargs++;
208 if (**p == ',')
209 (*p)++;
210 }
211 }
212
213 {
214 int i;
215 for (i = 0; i < nargs; i++)
216 {
217 debug_message(10, "Macro (%s) arg %d: %s", m -> name, i + 1, args[i]);
218 }
219 }
220
221 // step 2: iterate over the lines
222 if (as -> passnum == 2)
223 {
224 // pass 2 only - parse the lines and count them
225 for (lc = 0; lc < m -> numlines; lc++)
226 {
227 cl = cl -> next;
228 as -> skiplines++;
229 lwasm_parse_line(as, cl);
230 }
231 }
232 else
233 {
234 // pass 1 only - construct the lines and parse them
235 for (lc = 0; lc < m -> numlines; lc++)
236 {
237 nl = lwasm_alloc(sizeof(lwasm_line_t));
238 nl -> lineno = lc + 1;
239 nl -> filename = m -> name;
240 nl -> next = NULL;
241 nl -> prev = as -> linestail;
242 nl -> err = NULL;
243 nl -> fsize = 0;
244 nl -> sym = NULL;
245 nl -> bytes = NULL;
246 nl -> codelen = 0;
247 nl -> codesize = 0;
248 nl -> nocodelen = 0;
249 nl -> addrset = 0;
250 nl -> symaddr = -1;
251 nl -> badop = 0;
252 nl -> relocoff = -1;
253 if (as -> linestail)
254 as -> linestail -> next = nl;
255 as -> linestail = nl;
256 if (!(as -> lineshead))
257 as -> lineshead = nl;
258
259 bloc = blen = 0;
260 linebuff = NULL;
261 for (p2 = m -> lines[lc]; *p2; p2++)
262 {
263 if (*p2 == '\\' && isdigit(p2[1]))
264 {
265 int n;
266
267 p2++;
268 n = *p2 - '0';
269 if (n == 0)
270 {
271 for (p3 = m -> name; *p3; p3++)
272 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
273 continue;
274 }
275 if (n < 1 || n > nargs)
276 continue;
277 for (p3 = args[n - 1]; *p3; p3++)
278 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
279 continue;
280 }
281 else if (*p2 == '{')
282 {
283 int n = 0, n2;
284 p2++;
285 while (*p2 && isdigit(*p2))
286 {
287 n2 = *p2 - '0';
288 if (n2 < 0 || n2 > 9)
289 n2 = 0;
290 n = n * 10 + n2;
291 p2++;
292 }
293 if (*p2 == '}')
294 p2++;
295
296 if (n == 0)
297 {
298 for (p3 = m -> name; *p3; p3++)
299 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
300 continue;
301 }
302 if (n < 1 || n > nargs)
303 continue;
304 for (p3 = args[n - 1]; *p3; p3++)
305 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
306 continue;
307 }
308 else
309 {
310 macro_add_to_buff(&linebuff, &bloc, &blen, *p2);
311 }
312 }
313
314 macro_add_to_buff(&linebuff, &bloc, &blen, 0);
315
316 nl -> text = linebuff;
317
318 lwasm_parse_line(as, nl);
319 if (as -> endseen)
320 break;
321
322 }
323 }
324
325 // restore context from before the macro was called
326 as -> context = oldcontext;
327
328 // clean up
329 if (args)
330 {
331 while (nargs)
332 {
333 lwasm_free(args[--nargs]);
334 }
335 lwasm_free(args);
336 }
337
338 // indicate a macro was expanded
339 return 0;
340 }