comparison src/macro.c @ 57:035b95a3690f

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