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