1 %{ 2 /* 3 * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. 4 * 5 * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. 6 * Copyright (c) 2001, 2002 Adaptec Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer, 14 * without modification. 15 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16 * substantially similar to the "NO WARRANTY" disclaimer below 17 * ("Disclaimer") and any redistribution must be conditioned upon 18 * including a substantially similar Disclaimer requirement for further 19 * binary redistribution. 20 * 3. Neither the names of the above-listed copyright holders nor the names 21 * of any contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * Alternatively, this software may be distributed under the terms of the 25 * GNU General Public License ("GPL") version 2 as published by the Free 26 * Software Foundation. 27 * 28 * NO WARRANTY 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 38 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 * POSSIBILITY OF SUCH DAMAGES. 40 * 41 * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#20 $ 42 * 43 * $FreeBSD$ 44 */ 45 46 #include <sys/types.h> 47 48 #include <inttypes.h> 49 #include <limits.h> 50 #include <regex.h> 51 #include <stdio.h> 52 #include <string.h> 53 #include <sysexits.h> 54 #include "../queue.h" 55 56 #include "aicasm.h" 57 #include "aicasm_symbol.h" 58 #include "aicasm_gram.h" 59 60 /* This is used for macro body capture too, so err on the large size. */ 61 #define MAX_STR_CONST 4096 62 static char string_buf[MAX_STR_CONST]; 63 static char *string_buf_ptr; 64 static int parren_count; 65 static int quote_count; 66 static char buf[255]; 67 void mm_switch_to_buffer(YY_BUFFER_STATE); 68 void mmparse(); 69 void mm_delete_buffer(YY_BUFFER_STATE); 70 %} 71 72 PATH ([/]*[-A-Za-z0-9_.])+ 73 WORD [A-Za-z_][-A-Za-z_0-9]* 74 SPACE [ \t]+ 75 MCARG [^(), \t]+ 76 MBODY ((\\[^\n])*[^\n\\]*)+ 77 78 %x COMMENT 79 %x CEXPR 80 %x INCLUDE 81 %x STRING 82 %x MACRODEF 83 %x MACROARGLIST 84 %x MACROCALLARGS 85 %x MACROBODY 86 87 %% 88 \n { ++yylineno; } 89 \r ; 90 "/*" { BEGIN COMMENT; /* Enter comment eating state */ } 91 <COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); } 92 <COMMENT>\n { ++yylineno; } 93 <COMMENT>[^*/\n]* ; 94 <COMMENT>"*"+[^*/\n]* ; 95 <COMMENT>"/"+[^*/\n]* ; 96 <COMMENT>"*"+"/" { BEGIN INITIAL; } 97 if[ \t]*\( { 98 string_buf_ptr = string_buf; 99 parren_count = 1; 100 BEGIN CEXPR; 101 return T_IF; 102 } 103 <CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; } 104 <CEXPR>\) { 105 parren_count--; 106 if (parren_count == 0) { 107 /* All done */ 108 BEGIN INITIAL; 109 *string_buf_ptr = '\0'; 110 yylval.sym = symtable_get(string_buf); 111 return T_CEXPR; 112 } else { 113 *string_buf_ptr++ = ')'; 114 } 115 } 116 <CEXPR>\n { ++yylineno; } 117 <CEXPR>\r ; 118 <CEXPR>[^()\n]+ { 119 char *yptr; 120 121 yptr = yytext; 122 while (*yptr != '\0') { 123 /* Remove duplicate spaces */ 124 if (*yptr == '\t') 125 *yptr = ' '; 126 if (*yptr == ' ' 127 && string_buf_ptr != string_buf 128 && string_buf_ptr[-1] == ' ') 129 yptr++; 130 else 131 *string_buf_ptr++ = *yptr++; 132 } 133 } 134 else { return T_ELSE; } 135 VERSION { return T_VERSION; } 136 PREFIX { return T_PREFIX; } 137 PATCH_ARG_LIST { return T_PATCH_ARG_LIST; } 138 \" { 139 string_buf_ptr = string_buf; 140 BEGIN STRING; 141 } 142 <STRING>[^"]+ { 143 char *yptr; 144 145 yptr = yytext; 146 while (*yptr) 147 *string_buf_ptr++ = *yptr++; 148 } 149 <STRING>\" { 150 /* All done */ 151 BEGIN INITIAL; 152 *string_buf_ptr = '\0'; 153 yylval.str = string_buf; 154 return T_STRING; 155 } 156 {SPACE} ; 157 158 /* Register/SCB/SRAM definition keywords */ 159 export { return T_EXPORT; } 160 register { return T_REGISTER; } 161 const { yylval.value = FALSE; return T_CONST; } 162 download { return T_DOWNLOAD; } 163 address { return T_ADDRESS; } 164 count { return T_COUNT; } 165 access_mode { return T_ACCESS_MODE; } 166 dont_generate_debug_code { return T_DONT_GENERATE_DEBUG_CODE; } 167 modes { return T_MODES; } 168 RW|RO|WO { 169 if (strcmp(yytext, "RW") == 0) 170 yylval.value = RW; 171 else if (strcmp(yytext, "RO") == 0) 172 yylval.value = RO; 173 else 174 yylval.value = WO; 175 return T_MODE; 176 } 177 field { return T_FIELD; } 178 enum { return T_ENUM; } 179 mask { return T_MASK; } 180 alias { return T_ALIAS; } 181 size { return T_SIZE; } 182 scb { return T_SCB; } 183 scratch_ram { return T_SRAM; } 184 accumulator { return T_ACCUM; } 185 mode_pointer { return T_MODE_PTR; } 186 allones { return T_ALLONES; } 187 allzeros { return T_ALLZEROS; } 188 none { return T_NONE; } 189 sindex { return T_SINDEX; } 190 A { return T_A; } 191 192 /* Instruction Formatting */ 193 PAD_PAGE { return T_PAD_PAGE; } 194 BEGIN_CRITICAL { return T_BEGIN_CS; } 195 END_CRITICAL { return T_END_CS; } 196 SET_SRC_MODE { return T_SET_SRC_MODE; } 197 SET_DST_MODE { return T_SET_DST_MODE; } 198 199 /* Opcodes */ 200 shl { return T_SHL; } 201 shr { return T_SHR; } 202 ror { return T_ROR; } 203 rol { return T_ROL; } 204 mvi { return T_MVI; } 205 mov { return T_MOV; } 206 clr { return T_CLR; } 207 jmp { return T_JMP; } 208 jc { return T_JC; } 209 jnc { return T_JNC; } 210 je { return T_JE; } 211 jne { return T_JNE; } 212 jz { return T_JZ; } 213 jnz { return T_JNZ; } 214 call { return T_CALL; } 215 add { return T_ADD; } 216 adc { return T_ADC; } 217 bmov { return T_BMOV; } 218 inc { return T_INC; } 219 dec { return T_DEC; } 220 stc { return T_STC; } 221 clc { return T_CLC; } 222 cmp { return T_CMP; } 223 not { return T_NOT; } 224 xor { return T_XOR; } 225 test { return T_TEST;} 226 and { return T_AND; } 227 or { return T_OR; } 228 ret { return T_RET; } 229 nop { return T_NOP; } 230 231 /* ARP2 16bit extensions */ 232 /* or16 { return T_OR16; } */ 233 /* and16 { return T_AND16; }*/ 234 /* xor16 { return T_XOR16; }*/ 235 /* add16 { return T_ADD16; }*/ 236 /* adc16 { return T_ADC16; }*/ 237 /* mvi16 { return T_MVI16; }*/ 238 /* test16 { return T_TEST16; }*/ 239 /* cmp16 { return T_CMP16; }*/ 240 /* cmpxchg { return T_CMPXCHG; }*/ 241 242 /* Allowed Symbols */ 243 \<\< { return T_EXPR_LSHIFT; } 244 \>\> { return T_EXPR_RSHIFT; } 245 [-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; } 246 247 /* Number processing */ 248 0[0-7]* { 249 yylval.value = strtol(yytext, NULL, 8); 250 return T_NUMBER; 251 } 252 253 0[xX][0-9a-fA-F]+ { 254 yylval.value = strtoul(yytext + 2, NULL, 16); 255 return T_NUMBER; 256 } 257 258 [1-9][0-9]* { 259 yylval.value = strtol(yytext, NULL, 10); 260 return T_NUMBER; 261 } 262 /* Include Files */ 263 #include{SPACE} { 264 BEGIN INCLUDE; 265 quote_count = 0; 266 return T_INCLUDE; 267 } 268 <INCLUDE>[<] { return yytext[0]; } 269 <INCLUDE>[>] { BEGIN INITIAL; return yytext[0]; } 270 <INCLUDE>[\"] { 271 if (quote_count != 0) 272 BEGIN INITIAL; 273 quote_count++; 274 return yytext[0]; 275 } 276 <INCLUDE>{PATH} { 277 char *yptr; 278 279 yptr = yytext; 280 string_buf_ptr = string_buf; 281 while (*yptr) 282 *string_buf_ptr++ = *yptr++; 283 yylval.str = string_buf; 284 *string_buf_ptr = '\0'; 285 return T_PATH; 286 } 287 <INCLUDE>. { stop("Invalid include line", EX_DATAERR); } 288 #define{SPACE} { 289 BEGIN MACRODEF; 290 return T_DEFINE; 291 } 292 <MACRODEF>{WORD}{SPACE} { 293 char *yptr; 294 295 /* Strip space and return as a normal symbol */ 296 yptr = yytext; 297 while (*yptr != ' ' && *yptr != '\t') 298 yptr++; 299 *yptr = '\0'; 300 yylval.sym = symtable_get(yytext); 301 string_buf_ptr = string_buf; 302 BEGIN MACROBODY; 303 return T_SYMBOL; 304 } 305 <MACRODEF>{WORD}\( { 306 /* 307 * We store the symbol with its opening 308 * parren so we can differentiate macros 309 * that take args from macros with the 310 * same name that do not take args as 311 * is allowed in C. 312 */ 313 BEGIN MACROARGLIST; 314 yylval.sym = symtable_get(yytext); 315 unput('('); 316 return T_SYMBOL; 317 } 318 <MACROARGLIST>{WORD} { 319 yylval.str = yytext; 320 return T_ARG; 321 } 322 <MACROARGLIST>{SPACE} ; 323 <MACROARGLIST>[(,] { 324 return yytext[0]; 325 } 326 <MACROARGLIST>[)] { 327 string_buf_ptr = string_buf; 328 BEGIN MACROBODY; 329 return ')'; 330 } 331 <MACROARGLIST>. { 332 snprintf(buf, sizeof(buf), "Invalid character " 333 "'%c' in macro argument list", 334 yytext[0]); 335 stop(buf, EX_DATAERR); 336 } 337 <MACROCALLARGS>{SPACE} ; 338 <MACROCALLARGS>\( { 339 parren_count++; 340 if (parren_count == 1) 341 return ('('); 342 *string_buf_ptr++ = '('; 343 } 344 <MACROCALLARGS>\) { 345 parren_count--; 346 if (parren_count == 0) { 347 BEGIN INITIAL; 348 return (')'); 349 } 350 *string_buf_ptr++ = ')'; 351 } 352 <MACROCALLARGS>{MCARG} { 353 char *yptr; 354 355 yptr = yytext; 356 while (*yptr) 357 *string_buf_ptr++ = *yptr++; 358 } 359 <MACROCALLARGS>\, { 360 if (string_buf_ptr != string_buf) { 361 /* 362 * Return an argument and 363 * rescan this comma so we 364 * can return it as well. 365 */ 366 *string_buf_ptr = '\0'; 367 yylval.str = string_buf; 368 string_buf_ptr = string_buf; 369 unput(','); 370 return T_ARG; 371 } 372 return ','; 373 } 374 <MACROBODY>\\\n { 375 /* Eat escaped newlines. */ 376 ++yylineno; 377 } 378 <MACROBODY>\r ; 379 <MACROBODY>\n { 380 /* Macros end on the first unescaped newline. */ 381 BEGIN INITIAL; 382 *string_buf_ptr = '\0'; 383 yylval.str = string_buf; 384 ++yylineno; 385 return T_MACROBODY; 386 } 387 <MACROBODY>{MBODY} { 388 char *yptr; 389 char c; 390 391 yptr = yytext; 392 while (c = *yptr++) { 393 /* 394 * Strip carriage returns. 395 */ 396 if (c == '\r') 397 continue; 398 *string_buf_ptr++ = c; 399 } 400 } 401 {WORD}\( { 402 char *yptr; 403 char *ycopy; 404 405 /* May be a symbol or a macro invocation. */ 406 yylval.sym = symtable_get(yytext); 407 if (yylval.sym->type == MACRO) { 408 YY_BUFFER_STATE old_state; 409 YY_BUFFER_STATE temp_state; 410 411 ycopy = strdup(yytext); 412 yptr = ycopy + yyleng; 413 while (yptr > ycopy) 414 unput(*--yptr); 415 old_state = YY_CURRENT_BUFFER; 416 temp_state = 417 yy_create_buffer(stdin, 418 YY_BUF_SIZE); 419 yy_switch_to_buffer(temp_state); 420 mm_switch_to_buffer(old_state); 421 mmparse(); 422 mm_switch_to_buffer(temp_state); 423 yy_switch_to_buffer(old_state); 424 mm_delete_buffer(temp_state); 425 expand_macro(yylval.sym); 426 } else { 427 if (yylval.sym->type == UNINITIALIZED) { 428 /* Try without the '(' */ 429 symbol_delete(yylval.sym); 430 yytext[yyleng-1] = '\0'; 431 yylval.sym = 432 symtable_get(yytext); 433 } 434 unput('('); 435 return T_SYMBOL; 436 } 437 } 438 {WORD} { 439 yylval.sym = symtable_get(yytext); 440 if (yylval.sym->type == MACRO) { 441 expand_macro(yylval.sym); 442 } else { 443 return T_SYMBOL; 444 } 445 } 446 . { 447 snprintf(buf, sizeof(buf), "Invalid character " 448 "'%c'", yytext[0]); 449 stop(buf, EX_DATAERR); 450 } 451 %% 452 453 typedef struct include { 454 YY_BUFFER_STATE buffer; 455 int lineno; 456 char *filename; 457 SLIST_ENTRY(include) links; 458 }include_t; 459 460 SLIST_HEAD(, include) include_stack; 461 462 void 463 include_file(char *file_name, include_type type) 464 { 465 FILE *newfile; 466 include_t *include; 467 468 newfile = NULL; 469 /* Try the current directory first */ 470 if (includes_search_curdir != 0 || type == SOURCE_FILE) 471 newfile = fopen(file_name, "r"); 472 473 if (newfile == NULL && type != SOURCE_FILE) { 474 path_entry_t include_dir; 475 for (include_dir = search_path.slh_first; 476 include_dir != NULL; 477 include_dir = include_dir->links.sle_next) { 478 char fullname[PATH_MAX]; 479 480 if ((include_dir->quoted_includes_only == TRUE) 481 && (type != QUOTED_INCLUDE)) 482 continue; 483 484 snprintf(fullname, sizeof(fullname), 485 "%s/%s", include_dir->directory, file_name); 486 487 if ((newfile = fopen(fullname, "r")) != NULL) 488 break; 489 } 490 } 491 492 if (newfile == NULL) { 493 perror(file_name); 494 stop("Unable to open input file", EX_SOFTWARE); 495 /* NOTREACHED */ 496 } 497 498 if (type != SOURCE_FILE) { 499 include = (include_t *)malloc(sizeof(include_t)); 500 if (include == NULL) { 501 stop("Unable to allocate include stack entry", 502 EX_SOFTWARE); 503 /* NOTREACHED */ 504 } 505 include->buffer = YY_CURRENT_BUFFER; 506 include->lineno = yylineno; 507 include->filename = yyfilename; 508 SLIST_INSERT_HEAD(&include_stack, include, links); 509 } 510 yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); 511 yylineno = 1; 512 yyfilename = strdup(file_name); 513 } 514 515 static void next_substitution(struct symbol *mac_symbol, const char *body_pos, 516 const char **next_match, 517 struct macro_arg **match_marg, regmatch_t *match); 518 519 void 520 expand_macro(struct symbol *macro_symbol) 521 { 522 struct macro_arg *marg; 523 struct macro_arg *match_marg; 524 const char *body_head; 525 const char *body_pos; 526 const char *next_match; 527 528 /* 529 * Due to the nature of unput, we must work 530 * backwards through the macro body performing 531 * any expansions. 532 */ 533 body_head = macro_symbol->info.macroinfo->body; 534 body_pos = body_head + strlen(body_head); 535 while (body_pos > body_head) { 536 regmatch_t match; 537 538 next_match = body_head; 539 match_marg = NULL; 540 next_substitution(macro_symbol, body_pos, &next_match, 541 &match_marg, &match); 542 543 /* Put back everything up until the replacement. */ 544 while (body_pos > next_match) 545 unput(*--body_pos); 546 547 /* Perform the replacement. */ 548 if (match_marg != NULL) { 549 const char *strp; 550 551 next_match = match_marg->replacement_text; 552 strp = next_match + strlen(next_match); 553 while (strp > next_match) 554 unput(*--strp); 555 556 /* Skip past the unexpanded macro arg. */ 557 body_pos -= match.rm_eo - match.rm_so; 558 } 559 } 560 561 /* Cleanup replacement text. */ 562 STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { 563 free(marg->replacement_text); 564 } 565 } 566 567 /* 568 * Find the next substitution in the macro working backwards from 569 * body_pos until the beginning of the macro buffer. next_match 570 * should be initialized to the beginning of the macro buffer prior 571 * to calling this routine. 572 */ 573 static void 574 next_substitution(struct symbol *mac_symbol, const char *body_pos, 575 const char **next_match, struct macro_arg **match_marg, 576 regmatch_t *match) 577 { 578 regmatch_t matches[2]; 579 struct macro_arg *marg; 580 const char *search_pos; 581 int retval; 582 583 do { 584 search_pos = *next_match; 585 586 STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) { 587 588 retval = regexec(&marg->arg_regex, search_pos, 2, 589 matches, 0); 590 if (retval == 0 591 && (matches[1].rm_eo + search_pos) <= body_pos 592 && (matches[1].rm_eo + search_pos) > *next_match) { 593 *match = matches[1]; 594 *next_match = match->rm_eo + search_pos; 595 *match_marg = marg; 596 } 597 } 598 } while (search_pos != *next_match); 599 } 600 601 int 602 yywrap() 603 { 604 include_t *include; 605 606 yy_delete_buffer(YY_CURRENT_BUFFER); 607 (void)fclose(yyin); 608 if (yyfilename != NULL) 609 free(yyfilename); 610 yyfilename = NULL; 611 include = include_stack.slh_first; 612 if (include != NULL) { 613 yy_switch_to_buffer(include->buffer); 614 yylineno = include->lineno; 615 yyfilename = include->filename; 616 SLIST_REMOVE_HEAD(&include_stack, links); 617 free(include); 618 return (0); 619 } 620 return (1); 621 } 622