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