Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
3 | * Use is subject to license terms. | |
4 | */ | |
5 | ||
6 | %{ | |
7 | ||
8 | #pragma ident "@(#)aslex.l 1.2 07/02/12 SMI" | |
9 | ||
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
12 | #include <unistd.h> | |
13 | #include <stdarg.h> | |
14 | #include <errno.h> | |
15 | #include <sys/param.h> /* for MAXPATHLEN */ | |
16 | #include <string.h> /* for strchr & strdup */ | |
17 | #include <ctype.h> /* for islower / toupper */ | |
18 | ||
19 | #include <assert.h> | |
20 | ||
21 | #include "basics.h" | |
22 | #include "internal.h" | |
23 | #include "parser.h" | |
24 | ||
25 | ||
26 | int yywrap(); | |
27 | ||
28 | bool_t flag_debug = false; | |
29 | ||
30 | YYLTYPE yyloc; | |
31 | yylval_t yylval; | |
32 | ||
33 | int yy_line_num; | |
34 | ||
35 | #define UOP(_t, _size) { yylval.ldst.wordsize=(_size); yylval.ldst.signext=false; return (_t); } | |
36 | #define SOP(_t, _size) { yylval.ldst.wordsize=(_size); yylval.ldst.signext=true; return (_t); } | |
37 | ||
38 | void validate_op(token_t tok, ldst_t *ldstinfop, char *namep); | |
39 | ||
40 | %} | |
41 | ||
42 | %x comment | |
43 | %x string | |
44 | ||
45 | %% | |
46 | ||
47 | <<EOF>> { | |
48 | return T_eof; | |
49 | } | |
50 | ||
51 | "!"([^\n])*$ { | |
52 | DBG(printf("comment: %s\n", yytext);); | |
53 | } | |
54 | ||
55 | ^"#"([^\n])*$ { | |
56 | DBG(printf("directive: %s\n", yytext);); | |
57 | } | |
58 | ||
59 | "/*" { | |
60 | BEGIN(comment); | |
61 | DBG(printf("comment begin\n");); | |
62 | } | |
63 | ||
64 | <comment>\n { | |
65 | yy_line_num++; | |
66 | } | |
67 | ||
68 | <comment>. /* swallow */ | |
69 | ||
70 | <comment>"*/" { | |
71 | BEGIN(INITIAL); | |
72 | DBG(printf("comment end\n");); | |
73 | } | |
74 | ||
75 | "\"" { | |
76 | BEGIN(string); | |
77 | DBG(printf("string begin\n");); | |
78 | } | |
79 | ||
80 | <string>"\"" { | |
81 | BEGIN(INITIAL); | |
82 | DBG(printf("string end\n");); | |
83 | yylval.namep = NULL; /* dont care for now */ | |
84 | return T_string; | |
85 | } | |
86 | ||
87 | <string>\n { | |
88 | yy_line_num++; | |
89 | } | |
90 | ||
91 | <string>"\\\"" { /* escaped quote is part of string */ } | |
92 | ||
93 | <string>[^\"]* { /* swallow for now */ } | |
94 | ||
95 | ||
96 | "\n" { | |
97 | yyloc.first_line = | |
98 | yyloc.last_line = ++yy_line_num; | |
99 | return T_nl; | |
100 | } | |
101 | ||
102 | "ldsb" { SOP(T_load, 1); } | |
103 | ||
104 | "ldub" { UOP(T_load, 1); } | |
105 | ||
106 | "ldsh" { SOP(T_load, 2); } | |
107 | ||
108 | "lduh" { UOP(T_load, 2); } | |
109 | ||
110 | "ldsw" { SOP(T_load, 4); } | |
111 | ||
112 | "lduw" { UOP(T_load, 4); } | |
113 | ||
114 | "ldn" { UOP(T_load, 8); } | |
115 | ||
116 | "ldx" { UOP(T_load, 8); } | |
117 | ||
118 | "ldd" { UOP(T_load, 16); } | |
119 | ||
120 | "stb" { UOP(T_store, 1); } | |
121 | ||
122 | "sth" { UOP(T_store, 2); } | |
123 | ||
124 | "stw" { UOP(T_store, 4); } | |
125 | ||
126 | "stx" { UOP(T_store, 8); } | |
127 | ||
128 | "stn" { UOP(T_store, 8); } | |
129 | ||
130 | "std" { UOP(T_store, 16); } | |
131 | ||
132 | ^"."?[A-Za-z0-9_]+":" { | |
133 | yylval.namep = strdup(yytext); | |
134 | return T_labeldef; | |
135 | } | |
136 | ||
137 | "%"([a-z]+)([0-9]*) { | |
138 | yylval.namep = strdup(yytext); | |
139 | return T_register; | |
140 | } | |
141 | ||
142 | ([A-Za-z])([A-Za-z0-9_])* { | |
143 | yylval.namep = strdup(yytext); | |
144 | return T_name; | |
145 | } | |
146 | ||
147 | "0x"([1-9A-Fa-f])([0-9A-Fa-f])* { | |
148 | uint64_t val; | |
149 | val = strtoull(yytext, NULL, 16); | |
150 | yylval.val = val; | |
151 | return T_number; | |
152 | } | |
153 | ||
154 | "0x0" { | |
155 | yylval.val = 0; | |
156 | return T_number; | |
157 | } | |
158 | ||
159 | ([1-9])([0-9])* { | |
160 | uint64_t val; | |
161 | val = strtoull(yytext, NULL, 10); | |
162 | yylval.val = val; | |
163 | return T_number; | |
164 | } | |
165 | ||
166 | ||
167 | ([ \t])+ { /* swallow */ } | |
168 | ||
169 | . return yytext[0] ; | |
170 | ||
171 | %% | |
172 | ||
173 | ||
174 | ||
175 | ||
176 | ||
177 | ||
178 | int yywrap() | |
179 | { | |
180 | return 1; | |
181 | } | |
182 | ||
183 | ||
184 | void yyerror(char *strp) | |
185 | { | |
186 | fprintf(stderr,"error @ line %d: %s\n", | |
187 | yyloc.first_line, | |
188 | strp); | |
189 | exit(1); | |
190 | } | |
191 | ||
192 | ||
193 | static char *tok_to_str(int tok) | |
194 | { | |
195 | static char buf[2]; | |
196 | char * s; | |
197 | ||
198 | if (tok<256) { | |
199 | buf[0]=tok; | |
200 | buf[1]='\0'; | |
201 | return (char*)buf; | |
202 | } | |
203 | #define T(_t) case _t : s = #_t; break; | |
204 | switch(tok) { | |
205 | T(T_nl); | |
206 | T(T_name); | |
207 | T(T_labeldef); | |
208 | T(T_register); | |
209 | T(T_number); | |
210 | T(T_string); | |
211 | T(T_load); | |
212 | T(T_store); | |
213 | T(T_cas); | |
214 | default: s = "unknown"; | |
215 | } | |
216 | #undef T | |
217 | return s; | |
218 | } | |
219 | ||
220 | token_t get_token() | |
221 | { | |
222 | token_t tok; | |
223 | ||
224 | tok = yylex(); | |
225 | ||
226 | DBG( printf("Line %d : token %d : %s", | |
227 | yyloc.first_line, tok, tok_to_str(tok)); | |
228 | switch(tok) { | |
229 | case T_eof: printf("END OF FILE"); break; | |
230 | case T_name: printf(" : %s", yylval.namep); break; | |
231 | case T_labeldef: printf(" : %s", yylval.namep); break; | |
232 | case T_register: printf(" : %s", yylval.namep); break; | |
233 | case T_number: printf(" : 0x%llx", yylval.val); break; | |
234 | case T_cas: | |
235 | case T_store: | |
236 | case T_load: printf(" : %s : bytes=%d", | |
237 | yylval.ldst.signext ? "s" : "u", yylval.ldst.wordsize); | |
238 | break; | |
239 | default: | |
240 | break; | |
241 | } | |
242 | printf("\n"); | |
243 | ); | |
244 | ||
245 | return tok; | |
246 | } | |
247 | ||
248 | ||
249 | void free_yyval(token_t tok) | |
250 | { | |
251 | switch (tok) { | |
252 | case T_name: | |
253 | case T_labeldef: | |
254 | case T_register: | |
255 | free(yylval.namep); | |
256 | yylval.namep = NULL; | |
257 | break; | |
258 | default: | |
259 | break; | |
260 | } | |
261 | } | |
262 | ||
263 | ||
264 | /* | |
265 | * Ultra simple parser to pull out only load or store instructions | |
266 | * that fit a very basic template. | |
267 | */ | |
268 | ||
269 | void lex_only() | |
270 | { | |
271 | token_t tok, ldsttok, tok_left, tok_right; | |
272 | char *tok_left_ptr, *tok_right_ptr; | |
273 | ldst_t ldstinfo; | |
274 | ||
275 | while ((tok = get_token())!=T_eof) { | |
276 | DBG( printf("Start line with token %d\n", tok); ); | |
277 | if (tok == T_nl) { | |
278 | continue; | |
279 | } | |
280 | ||
281 | /* | |
282 | * Look for a load or store at the beginning of a line. | |
283 | * if not found - swallow the line and move to the next. | |
284 | * A line may also be allowed to have an initial label def. | |
285 | */ | |
286 | if (tok == T_labeldef) { | |
287 | free_yyval(tok); | |
288 | tok = get_token(); | |
289 | if (tok==T_eof) break; | |
290 | if (tok == T_nl) continue; | |
291 | } | |
292 | ||
293 | DBG( printf("look for memop %d\n", tok); ); | |
294 | ||
295 | tok_left = -1; | |
296 | tok_right = -1; | |
297 | tok_left_ptr = NULL; | |
298 | tok_right_ptr = NULL; | |
299 | ||
300 | if (tok != T_load && tok != T_store) goto swallow; | |
301 | ||
302 | ldsttok = tok; | |
303 | ldstinfo = yylval.ldst; | |
304 | ||
305 | if (tok == T_store) goto handle_store; | |
306 | DBG( printf("Handle load\n"); ); | |
307 | ||
308 | tok = get_token(); | |
309 | if (tok != '[') goto swallow; | |
310 | ||
311 | tok = get_token(); | |
312 | if (tok != T_register && tok != T_name && tok != T_number) goto swallow; | |
313 | tok_left = tok; | |
314 | tok_left_ptr = yylval.namep; | |
315 | ||
316 | /* only want a + b forms */ | |
317 | tok = get_token(); | |
318 | if (tok != '+') goto cleanup; | |
319 | ||
320 | tok = get_token(); | |
321 | if (tok != T_register && tok != T_name && tok != T_number) goto cleanup; | |
322 | tok_right = tok; | |
323 | tok_right_ptr = yylval.namep; | |
324 | ||
325 | tok = get_token(); | |
326 | if (tok != ']') goto cleanup; | |
327 | ||
328 | DBG( printf("Load accepted\n"); ); | |
329 | ||
330 | goto sanity_check; | |
331 | ||
332 | ||
333 | ||
334 | ||
335 | handle_store:; | |
336 | DBG( printf("Handle store\n");); | |
337 | ||
338 | tok = get_token(); | |
339 | if (tok != T_register) goto swallow; | |
340 | ||
341 | tok = get_token(); | |
342 | if (tok != ',') goto swallow; | |
343 | ||
344 | tok = get_token(); | |
345 | if (tok != '[') goto swallow; | |
346 | ||
347 | tok = get_token(); | |
348 | if (tok != T_register && tok != T_name && tok != T_number) goto swallow; | |
349 | tok_left = tok; | |
350 | tok_left_ptr = yylval.namep; | |
351 | ||
352 | /* only want a + b forms */ | |
353 | tok = get_token(); | |
354 | if (tok != '+') goto cleanup; | |
355 | ||
356 | tok = get_token(); | |
357 | if (tok != T_register && tok != T_name && tok != T_number) goto cleanup; | |
358 | tok_right = tok; | |
359 | tok_right_ptr = yylval.namep; | |
360 | ||
361 | tok = get_token(); | |
362 | if (tok != ']') goto cleanup; | |
363 | ||
364 | DBG( printf("Store accepted\n"); ); | |
365 | ||
366 | goto sanity_check; | |
367 | ||
368 | ||
369 | ||
370 | /* | |
371 | * Finally the check we care about ... | |
372 | */ | |
373 | ||
374 | sanity_check:; | |
375 | /* | |
376 | * The load/store operands can be given in any order - | |
377 | * register + offset or offset + register ... so to make things easier | |
378 | * if we find one form we swap the paramaters to give us the other. | |
379 | */ | |
380 | ||
381 | /* one side must have a name for us to check */ | |
382 | ||
383 | if (tok_left != T_name && tok_right != T_name) goto cleanup; | |
384 | ||
385 | /* | |
386 | * if both sides are a name - we bail since there is likely more than one type | |
387 | * for us to have to sanity check .. i.e. %g3 + BASE_OFSET + FOOBAR | |
388 | */ | |
389 | if (tok_left == T_name && tok_right == T_name) goto cleanup; | |
390 | ||
391 | /* now for the switch over */ | |
392 | ||
393 | if (tok_left == T_name) { | |
394 | token_t temptok; | |
395 | char *tempptr; | |
396 | ||
397 | temptok = tok_left; | |
398 | tempptr = tok_left_ptr; | |
399 | tok_left = tok_right; | |
400 | tok_left_ptr = tok_right_ptr; | |
401 | tok_right = temptok; | |
402 | tok_right_ptr = tempptr; | |
403 | } | |
404 | ||
405 | /* finally something we can validate ... */ | |
406 | ||
407 | DBG( printf("Validation of name %s\n", tok_right_ptr); ); | |
408 | ||
409 | validate_op(ldsttok, &ldstinfo, tok_right_ptr); | |
410 | ||
411 | goto cleanup; | |
412 | ||
413 | ||
414 | cleanup:; | |
415 | if (tok_left == T_name || tok_left == T_register) { | |
416 | free(tok_left_ptr); | |
417 | } | |
418 | if (tok_left == T_name || tok_left == T_register) { | |
419 | free(tok_left_ptr); | |
420 | } | |
421 | goto swallow; | |
422 | ||
423 | swallow_loop:; | |
424 | tok = get_token(); | |
425 | if (tok==T_eof) break; | |
426 | swallow:; | |
427 | free_yyval(tok); | |
428 | if (tok!=T_nl) goto swallow_loop; | |
429 | } | |
430 | } | |
431 | ||
432 | ||
433 | ||
434 | ||
435 | void validate_op(token_t ldsttok, ldst_t *ldstinfop, char *namep) | |
436 | { | |
437 | symbol_t *symp; | |
438 | ||
439 | symp = hash_find(namep); | |
440 | if (symp == NULL) { | |
441 | if (!flag_suppress_unknowns) { | |
442 | fprintf(stderr,"%s:%d : Warning: unknown symbol \'%s\' for memop\n", | |
443 | yyloc.fnamep, yyloc.first_line, namep); | |
444 | warning_count++; | |
445 | } | |
446 | return; | |
447 | } | |
448 | ||
449 | /* Compare sizes */ | |
450 | if (symp->size != ldstinfop->wordsize) { | |
451 | fprintf(stderr,"%s:%d : Warning: access size mismatch using symbol \'%s\'\n", | |
452 | yyloc.fnamep, yyloc.first_line, namep); | |
453 | fprintf(stderr,"\tAccess uses %d byte memop, but should be a %d byte memop\n", | |
454 | ldstinfop->wordsize, symp->size); | |
455 | warning_count++; | |
456 | } | |
457 | ||
458 | /* if its a load compare sign extension */ | |
459 | ||
460 | if (ldsttok == T_load) { | |
461 | if (ldstinfop->signext && ((symp->flags & Sym_unsigned)!=0)) { | |
462 | fprintf(stderr,"%s:%d : Warning: sign extension mismatch for symbol \'%s\'\n", | |
463 | yyloc.fnamep, yyloc.first_line, namep); | |
464 | fprintf(stderr,"\tAccess uses signed memop, but should be unsigned\n"); | |
465 | warning_count++; | |
466 | } else | |
467 | if (!ldstinfop->signext && ((symp->flags & Sym_signed)!=0)) { | |
468 | fprintf(stderr,"%s:%d : Warning: sign extension mismatch for symbol \'%s\'\n", | |
469 | yyloc.fnamep, yyloc.first_line, namep); | |
470 | fprintf(stderr,"\tAccess uses unsigned memop, but should be signed\n"); | |
471 | warning_count++; | |
472 | } | |
473 | } | |
474 | } |