Mercurial > hg > index.cgi
comparison lwasm/pass1.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 pass1.c | |
3 | |
4 Copyright © 2010 William Astle | |
5 | |
6 This file is part of LWTOOLS. | |
7 | |
8 LWTOOLS is free software: you can redistribute it and/or modify it under the | |
9 terms of the GNU General Public License as published by the Free Software | |
10 Foundation, either version 3 of the License, or (at your option) any later | |
11 version. | |
12 | |
13 This program is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 more details. | |
17 | |
18 You should have received a copy of the GNU General Public License along with | |
19 this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include <stdio.h> | |
23 #include <string.h> | |
24 | |
25 #include <lw_alloc.h> | |
26 #include <lw_string.h> | |
27 | |
28 #include "lwasm.h" | |
29 #include "instab.h" | |
30 #include "input.h" | |
31 | |
32 extern int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc); | |
33 extern int expand_struct(asmstate_t *as, line_t *l, char **p, char *opc); | |
34 | |
35 /* | |
36 pass 1: parse the lines | |
37 | |
38 line format: | |
39 | |
40 [<symbol>] <opcode> <operand>[ <comment>] | |
41 | |
42 If <symbol> is followed by a :, whitespace may precede the symbol | |
43 | |
44 A line may optionally start with a number which must not be preceded by | |
45 white space and must be followed by a single whitespace character. After | |
46 that whitespace character, the line is parsed as if it had no line number. | |
47 | |
48 */ | |
49 void do_pass1(asmstate_t *as) | |
50 { | |
51 char *line; | |
52 line_t *cl; | |
53 char *p1; | |
54 int stspace; | |
55 char *tok, *sym; | |
56 int opnum; | |
57 int lc = 1; | |
58 for (;;) | |
59 { | |
60 sym = NULL; | |
61 line = input_readline(as); | |
62 if (!line) | |
63 break; | |
64 if (line[0] == 1 && line[1] == 1) | |
65 { | |
66 // special internal directive | |
67 // these DO NOT appear in the output anywhere | |
68 // they are generated by the parser to pass information | |
69 // forward | |
70 for (p1 = line + 2; *p1 && !isspace(*p1); p1++) | |
71 /* do nothing */ ; | |
72 *p1++ = '\0'; | |
73 if (!strcmp(line + 2, "SETCONTEXT")) | |
74 { | |
75 as -> context = strtol(p1, NULL, 10); | |
76 } | |
77 lw_free(line); | |
78 lc = 1; | |
79 continue; | |
80 } | |
81 debug_message(as, 75, "Read line: %s", line); | |
82 | |
83 cl = lw_alloc(sizeof(line_t)); | |
84 memset(cl, 0, sizeof(line_t)); | |
85 cl -> outputl = -1; | |
86 cl -> linespec = lw_strdup(input_curspec(as)); | |
87 cl -> prev = as -> line_tail; | |
88 cl -> insn = -1; | |
89 cl -> as = as; | |
90 cl -> inmod = as -> inmod; | |
91 cl -> csect = as -> csect; | |
92 cl -> pragmas = as -> pragmas; | |
93 cl -> context = as -> context; | |
94 cl -> ltext = lw_strdup(line); | |
95 cl -> soff = -1; | |
96 cl -> dshow = -1; | |
97 cl -> dsize = 0; | |
98 cl -> dptr = NULL; | |
99 cl -> isbrpt = 0; | |
100 as -> cl = cl; | |
101 if (!as -> line_tail) | |
102 { | |
103 as -> line_head = cl; | |
104 cl -> addr = lw_expr_build(lw_expr_type_int, 0); | |
105 } | |
106 else | |
107 { | |
108 lw_expr_t te; | |
109 | |
110 cl -> lineno = as -> line_tail -> lineno + 1; | |
111 as -> line_tail -> next = cl; | |
112 | |
113 // set the line address | |
114 te = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, cl -> prev); | |
115 cl -> addr = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, cl -> prev -> addr, te); | |
116 lw_expr_destroy(te); | |
117 lwasm_reduce_expr(as, cl -> addr); | |
118 // lw_expr_simplify(cl -> addr, as); | |
119 | |
120 // carry DP value forward | |
121 cl -> dpval = cl -> prev -> dpval; | |
122 | |
123 } | |
124 if (!lc && strcmp(cl -> linespec, cl -> prev -> linespec)) | |
125 lc = 1; | |
126 if (lc) | |
127 { | |
128 cl -> lineno = 1; | |
129 lc = 0; | |
130 } | |
131 as -> line_tail = cl; | |
132 // blank lines don't count for anything | |
133 // except a local symbol context break | |
134 if (!*line) | |
135 { | |
136 as -> context = lwasm_next_context(as); | |
137 goto nextline; | |
138 } | |
139 | |
140 // skip comments | |
141 // commends do not create a context break | |
142 if (*line == '*' || *line == ';' || *line == '#') | |
143 goto nextline; | |
144 | |
145 p1 = line; | |
146 if (isdigit(*p1)) | |
147 { | |
148 // skip line number | |
149 while (*p1 && isdigit(*p1)) | |
150 p1++; | |
151 if (!*p1 && !isspace(*p1)) | |
152 p1 = line; | |
153 else if (*p1 && !isspace(*p1)) | |
154 p1 = line; | |
155 else if (*p1 && isspace(*p1)) | |
156 p1++; | |
157 } | |
158 | |
159 // blank line - context break | |
160 if (!*p1) | |
161 { | |
162 as -> context = lwasm_next_context(as); | |
163 goto nextline; | |
164 } | |
165 | |
166 // comment - no context break | |
167 if (*p1 == '*' || *p1 == ';' || *p1 == '#') | |
168 goto nextline; | |
169 | |
170 if (isspace(*p1)) | |
171 { | |
172 for (; *p1 && isspace(*p1); p1++) | |
173 /* do nothing */ ; | |
174 stspace = 1; | |
175 } | |
176 else | |
177 stspace = 0; | |
178 | |
179 if (*p1 == '*' || *p1 == ';' || *p1 == '#') | |
180 goto nextline; | |
181 if (!*p1) | |
182 { | |
183 // nothing but whitespace - context break | |
184 as -> context = lwasm_next_context(as); | |
185 goto nextline; | |
186 } | |
187 | |
188 // find the end of the first token | |
189 for (tok = p1; *p1 && !isspace(*p1) && *p1 != ':' && *p1 != '='; p1++) | |
190 /* do nothing */ ; | |
191 | |
192 if (*p1 == ':' || *p1 == '=' || stspace == 0) | |
193 { | |
194 // have a symbol here | |
195 sym = lw_strndup(tok, p1 - tok); | |
196 if (*p1 == ':') | |
197 p1++; | |
198 for (; *p1 && isspace(*p1); p1++) | |
199 /* do nothing */ ; | |
200 | |
201 if (*p1 == '=') | |
202 { | |
203 tok = p1++; | |
204 } | |
205 else | |
206 { | |
207 for (tok = p1; *p1 && !isspace(*p1); p1++) | |
208 /* do nothing */ ; | |
209 } | |
210 } | |
211 if (sym && strcmp(sym, "!") == 0) | |
212 cl -> isbrpt = 1; | |
213 else if (sym) | |
214 cl -> sym = lw_strdup(sym); | |
215 cl -> symset = 0; | |
216 | |
217 // tok points to the opcode for the line or NUL if none | |
218 if (*tok) | |
219 { | |
220 // look up operation code | |
221 sym = lw_strndup(tok, p1 - tok); | |
222 for (; *p1 && isspace(*p1); p1++) | |
223 /* do nothing */ ; | |
224 | |
225 for (opnum = 0; instab[opnum].opcode; opnum++) | |
226 { | |
227 if (!strcasecmp(instab[opnum].opcode, sym)) | |
228 break; | |
229 } | |
230 | |
231 // p1 points to the start of the operand | |
232 | |
233 // if we're inside a macro definition and not at ENDM, | |
234 // add the line to the macro definition and continue | |
235 if (as -> inmacro && !(instab[opnum].flags & lwasm_insn_endm)) | |
236 { | |
237 add_macro_line(as, line); | |
238 goto linedone; | |
239 } | |
240 | |
241 // if skipping a condition and the operation code doesn't | |
242 // operate within a condition (not a conditional) | |
243 // do nothing | |
244 if (as -> skipcond && !(instab[opnum].flags & lwasm_insn_cond)) | |
245 goto linedone; | |
246 | |
247 if (instab[opnum].opcode == NULL) | |
248 { | |
249 cl -> insn = -1; | |
250 if (*tok != ';' && *tok != '*') | |
251 { | |
252 // bad opcode; check for macro here | |
253 if (expand_macro(as, cl, &p1, sym) != 0) | |
254 { | |
255 // macro expansion failed | |
256 if (expand_struct(as, cl, &p1, sym) != 0) | |
257 { | |
258 // structure expansion failed | |
259 lwasm_register_error(as, cl, "Bad opcode"); | |
260 } | |
261 } | |
262 } | |
263 } | |
264 else | |
265 { | |
266 cl -> insn = opnum; | |
267 // no parse func means operand doesn't matter | |
268 if (instab[opnum].parse) | |
269 { | |
270 if (as -> instruct == 0 || instab[opnum].flags & lwasm_insn_struct) | |
271 { | |
272 cl -> len = -1; | |
273 // call parse function | |
274 (instab[opnum].parse)(as, cl, &p1); | |
275 | |
276 if (*p1 && !isspace(*p1)) | |
277 { | |
278 // flag bad operand error | |
279 lwasm_register_error(as, cl, "Bad operand (%s)", p1); | |
280 } | |
281 } | |
282 else if (as -> instruct == 1) | |
283 { | |
284 lwasm_register_error(as, cl, "Bad operand (%s)", p1); | |
285 } | |
286 } | |
287 } | |
288 } | |
289 | |
290 linedone: | |
291 lw_free(sym); | |
292 | |
293 if (!as -> skipcond && !as -> inmacro) | |
294 { | |
295 if (cl -> sym && cl -> symset == 0) | |
296 { | |
297 debug_message(as, 50, "Register symbol %s: %s", cl -> sym, lw_expr_print(cl -> addr)); | |
298 | |
299 // register symbol at line address | |
300 if (!register_symbol(as, cl, cl -> sym, cl -> addr, symbol_flag_none)) | |
301 { | |
302 // symbol error | |
303 // lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym); | |
304 } | |
305 } | |
306 debug_message(as, 40, "Line address: %s", lw_expr_print(cl -> addr)); | |
307 } | |
308 | |
309 nextline: | |
310 lw_free(line); | |
311 | |
312 // if we've hit the "end" bit, finish out | |
313 if (as -> endseen) | |
314 return; | |
315 } | |
316 } |