comparison lwasm/macro.c @ 0:2c24602be78f

Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author lost@l-w.ca
date Wed, 19 Jan 2011 22:27:17 -0700
parents
children 7317fbe024af
comparison
equal deleted inserted replaced
-1:000000000000 0:2c24602be78f
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 <stdio.h>
27
28 #include <lw_alloc.h>
29 #include <lw_string.h>
30
31 #include "lwasm.h"
32 #include "input.h"
33 #include "instab.h"
34
35 PARSEFUNC(pseudo_parse_macro)
36 {
37 macrotab_t *m;
38
39 l -> len = 0;
40
41 if (as -> skipcond)
42 {
43 as -> skipmacro = 1;
44 return;
45 }
46
47 if (as -> inmacro)
48 {
49 lwasm_register_error(as, l, "Attempt to define a macro inside a macro");
50 return;
51 }
52
53 if (!(l -> sym))
54 {
55 lwasm_register_error(as, l, "Missing macro name");
56 return;
57 }
58
59 for (m = as -> macros; m; m = m -> next)
60 {
61 if (!strcmp(m -> name, l -> sym))
62 break;
63 }
64 if (m)
65 {
66 lwasm_register_error(as, l, "Duplicate macro definition");
67 return;
68 }
69
70 m = lw_alloc(sizeof(macrotab_t));
71 m -> name = lw_strdup(l -> sym);
72 m -> next = as -> macros;
73 m -> lines = NULL;
74 m -> numlines = 0;
75 as -> macros = m;
76
77 while (**p && !isspace(**p))
78 (*p)++;
79
80 as -> inmacro = 1;
81 }
82
83 PARSEFUNC(pseudo_parse_endm)
84 {
85 l -> len = 0;
86
87 if (as -> skipcond)
88 {
89 as -> skipmacro = 0;
90 return;
91 }
92
93 if (!as -> inmacro)
94 {
95 lwasm_register_error(as, l, "ENDM without MACRO");
96 return;
97 }
98
99 as -> inmacro = 0;
100
101 // a macro definition counts as a context break for local symbols
102 as -> context = lwasm_next_context(as);
103 }
104
105 // the current macro will ALWAYS be the first one in the table
106 int add_macro_line(asmstate_t *as, char *optr)
107 {
108 if (!as -> inmacro)
109 return 0;
110
111 as -> macros -> lines = lw_realloc(as -> macros -> lines, sizeof(char *) * (as -> macros -> numlines + 1));
112 as -> macros -> lines[as -> macros -> numlines] = lw_strdup(optr);
113 as -> macros -> numlines += 1;
114 return 1;
115 }
116
117 void macro_add_to_buff(char **buff, int *loc, int *len, char c)
118 {
119 if (*loc == *len)
120 {
121 *buff = lw_realloc(*buff, *len + 32);
122 *len += 32;
123 }
124 (*buff)[(*loc)++] = c;
125 }
126
127 // this is just like a regular operation function
128 /*
129 macro args are referenced by "\n" where 1 <= n <= 9
130 or by "\{n}"; a \ can be included by writing \\
131 a comma separates argument but one can be included with "\,"
132 whitespace ends argument list but can be included with "\ " or the like
133
134 */
135 int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc)
136 {
137 int lc;
138 line_t *cl, *nl;
139 int oldcontext;
140 macrotab_t *m;
141
142 char **args = NULL; // macro arguments
143 int nargs = 0; // number of arguments
144
145 char *p2, *p3;
146
147 int bloc, blen;
148 char *linebuff;
149
150 for (m = as -> macros; m; m = m -> next)
151 {
152 if (!strcmp(opc, m -> name))
153 break;
154 }
155 // signal no macro expansion
156 if (!m)
157 return -1;
158
159 // save current symbol context for after macro expansion
160 oldcontext = as -> context;
161
162 cl = l;
163
164 as -> context = lwasm_next_context(as);
165
166 while (**p && !isspace(**p) && **p != ',')
167 {
168 p2 = *p;
169 while (*p2 && !isspace(*p2) && *p2 != ',')
170 {
171 if (*p2 == '\\')
172 {
173 if (p2[1])
174 p2++;
175 }
176 p2++;
177 }
178
179 // have arg here
180 args = lw_realloc(args, sizeof(char *) * (nargs + 1));
181 args[nargs] = lw_alloc(p2 - *p + 1);
182 args[nargs][p2 - *p] = '\0';
183 memcpy(args[nargs], *p, p2 - *p);
184 *p = p2;
185
186 // now collapse out "\" characters
187 for (p3 = p2 = args[nargs]; *p2; p2++, p3++)
188 {
189 if (*p2 == '\\' && p2[1])
190 {
191 p2++;
192 }
193 *p3 = *p2;
194 }
195 *p3 = '\0';
196
197 nargs++;
198 if (**p == ',')
199 (*p)++;
200 }
201
202
203 // now create a string for the macro
204 // and push it into the front of the input stack
205 bloc = blen = 0;
206 linebuff = NULL;
207
208 for (lc = 0; lc < m -> numlines; lc++)
209 {
210 for (p2 = m -> lines[lc]; *p2; p2++)
211 {
212 if (*p2 == '\\' && isdigit(p2[1]))
213 {
214 int n;
215
216 p2++;
217 n = *p2 - '0';
218 if (n == 0)
219 {
220 for (p3 = m -> name; *p3; p3++)
221 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
222 continue;
223 }
224 if (n < 1 || n > nargs)
225 continue;
226 for (p3 = args[n - 1]; *p3; p3++)
227 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
228 continue;
229 }
230 else if (*p2 == '{')
231 {
232 int n = 0, n2;
233 p2++;
234 while (*p2 && isdigit(*p2))
235 {
236 n2 = *p2 - '0';
237 if (n2 < 0 || n2 > 9)
238 n2 = 0;
239 n = n * 10 + n2;
240 p2++;
241 }
242 if (*p2 == '}')
243 p2++;
244
245 if (n == 0)
246 {
247 for (p3 = m -> name; *p3; p3++)
248 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
249 continue;
250 }
251 if (n < 1 || n > nargs)
252 continue;
253 for (p3 = args[n - 1]; *p3; p3++)
254 macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
255 continue;
256 }
257 else
258 {
259 macro_add_to_buff(&linebuff, &bloc, &blen, *p2);
260 }
261 }
262
263 macro_add_to_buff(&linebuff, &bloc, &blen, '\n');
264
265 }
266
267 {
268 char ctcbuf[100];
269 char *p;
270 snprintf(ctcbuf, 100, "\001\001SETCONTEXT %d\n", oldcontext);
271 for (p = ctcbuf; *p; p++)
272 macro_add_to_buff(&linebuff, &bloc, &blen, *p);
273 }
274
275 // push the macro into the front of the stream
276 input_openstring(as, opc, linebuff);
277
278 lw_free(linebuff);
279
280 // clean up
281 if (args)
282 {
283 while (nargs)
284 {
285 lw_free(args[--nargs]);
286 }
287 lw_free(args);
288 }
289
290 // indicate a macro was expanded
291 return 0;
292 }