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