comparison old-trunk/lwasm/old/macro.c @ 339:eb230fa7d28e

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