Mercurial > hg-old > index.cgi
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 } |