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