| 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 | } |