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 }