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