aicasm_scan.l revision 213845
1284677Sdim%{ 2284677Sdim/*- 3284677Sdim * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. 4284677Sdim * 5284677Sdim * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. 6284677Sdim * Copyright (c) 2001, 2002 Adaptec Inc. 7284677Sdim * All rights reserved. 8284677Sdim * 9284677Sdim * Redistribution and use in source and binary forms, with or without 10284677Sdim * modification, are permitted provided that the following conditions 11284677Sdim * are met: 12284677Sdim * 1. Redistributions of source code must retain the above copyright 13284677Sdim * notice, this list of conditions, and the following disclaimer, 14284677Sdim * without modification. 15284677Sdim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16284677Sdim * substantially similar to the "NO WARRANTY" disclaimer below 17284677Sdim * ("Disclaimer") and any redistribution must be conditioned upon 18284677Sdim * including a substantially similar Disclaimer requirement for further 19284677Sdim * binary redistribution. 20284677Sdim * 3. Neither the names of the above-listed copyright holders nor the names 21284677Sdim * of any contributors may be used to endorse or promote products derived 22284677Sdim * from this software without specific prior written permission. 23284677Sdim * 24284677Sdim * Alternatively, this software may be distributed under the terms of the 25284677Sdim * GNU General Public License ("GPL") version 2 as published by the Free 26284677Sdim * Software Foundation. 27284677Sdim * 28284677Sdim * NO WARRANTY 29284677Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30284677Sdim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31284677Sdim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 32284677Sdim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33284677Sdim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34284677Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35284677Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36284677Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37284677Sdim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 38284677Sdim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39284677Sdim * POSSIBILITY OF SUCH DAMAGES. 40284677Sdim * 41284677Sdim * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#19 $ 42284677Sdim * 43284677Sdim * $FreeBSD: head/sys/dev/aic7xxx/aicasm/aicasm_scan.l 213845 2010-10-14 19:19:19Z rpaulo $ 44284677Sdim */ 45284677Sdim 46284677Sdim#include <sys/types.h> 47284677Sdim 48284677Sdim#include <inttypes.h> 49284677Sdim#include <limits.h> 50284677Sdim#include <regex.h> 51284677Sdim#include <stdio.h> 52284677Sdim#include <string.h> 53284677Sdim#include <sysexits.h> 54284677Sdim#ifdef __linux__ 55284677Sdim#include "../queue.h" 56284677Sdim#else 57284677Sdim#include <sys/queue.h> 58284677Sdim#endif 59284677Sdim 60284677Sdim#include "aicasm.h" 61284677Sdim#include "aicasm_symbol.h" 62284677Sdim#include "aicasm_gram.h" 63284677Sdim 64284677Sdim/* This is used for macro body capture too, so err on the large size. */ 65284677Sdim#define MAX_STR_CONST 4096 66284677Sdimstatic char string_buf[MAX_STR_CONST]; 67284677Sdimstatic char *string_buf_ptr; 68284677Sdimstatic int parren_count; 69284677Sdimstatic int quote_count; 70284677Sdimstatic char msgbuf[255]; 71284677Sdim 72284677Sdimextern int yylex(void); 73284677Sdimextern int mmlex(void); 74284677Sdimextern int mmparse(void); 75284677Sdimextern void mm_switch_to_buffer(YY_BUFFER_STATE); 76284677Sdimextern void mm_delete_buffer(YY_BUFFER_STATE); 77296417Sdim%} 78296417Sdim 79296417SdimPATH ([/]*[-A-Za-z0-9_.])+ 80284677SdimWORD [A-Za-z_][-A-Za-z_0-9]* 81284677SdimSPACE [ \t]+ 82284677SdimMCARG [^(), \t]+ 83284677SdimMBODY ((\\[^\n])*[^\n\\]*)+ 84284677Sdim 85296417Sdim%x COMMENT 86296417Sdim%x CEXPR 87296417Sdim%x INCLUDE 88296417Sdim%x STRING 89296417Sdim%x MACRODEF 90296417Sdim%x MACROARGLIST 91296417Sdim%x MACROCALLARGS 92296417Sdim%x MACROBODY 93296417Sdim 94296417Sdim%% 95296417Sdim\n { ++yylineno; } 96296417Sdim\r ; 97296417Sdim"/*" { BEGIN COMMENT; /* Enter comment eating state */ } 98296417Sdim<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); } 99296417Sdim<COMMENT>\n { ++yylineno; } 100296417Sdim<COMMENT>[^*/\n]* ; 101296417Sdim<COMMENT>"*"+[^*/\n]* ; 102296417Sdim<COMMENT>"/"+[^*/\n]* ; 103296417Sdim<COMMENT>"*"+"/" { BEGIN INITIAL; } 104296417Sdimif[ \t]*\( { 105296417Sdim string_buf_ptr = string_buf; 106296417Sdim parren_count = 1; 107296417Sdim BEGIN CEXPR; 108296417Sdim return T_IF; 109296417Sdim } 110296417Sdim<CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; } 111296417Sdim<CEXPR>\) { 112296417Sdim parren_count--; 113296417Sdim if (parren_count == 0) { 114296417Sdim /* All done */ 115296417Sdim BEGIN INITIAL; 116296417Sdim *string_buf_ptr = '\0'; 117296417Sdim yylval.sym = symtable_get(string_buf); 118296417Sdim return T_CEXPR; 119296417Sdim } else { 120296417Sdim *string_buf_ptr++ = ')'; 121296417Sdim } 122296417Sdim } 123296417Sdim<CEXPR>\n { ++yylineno; } 124296417Sdim<CEXPR>\r ; 125296417Sdim<CEXPR>[^()\n]+ { 126296417Sdim char *yptr; 127296417Sdim 128296417Sdim yptr = yytext; 129296417Sdim while (*yptr != '\0') { 130296417Sdim /* Remove duplicate spaces */ 131296417Sdim if (*yptr == '\t') 132296417Sdim *yptr = ' '; 133296417Sdim if (*yptr == ' ' 134296417Sdim && string_buf_ptr != string_buf 135296417Sdim && string_buf_ptr[-1] == ' ') 136296417Sdim yptr++; 137296417Sdim else 138296417Sdim *string_buf_ptr++ = *yptr++; 139296417Sdim } 140296417Sdim } 141296417Sdim 142296417SdimVERSION { return T_VERSION; } 143296417SdimPREFIX { return T_PREFIX; } 144296417SdimPATCH_ARG_LIST { return T_PATCH_ARG_LIST; } 145296417Sdim\" { 146296417Sdim string_buf_ptr = string_buf; 147296417Sdim BEGIN STRING; 148296417Sdim } 149296417Sdim<STRING>[^"]+ { 150296417Sdim char *yptr; 151296417Sdim 152296417Sdim yptr = yytext; 153296417Sdim while (*yptr) 154296417Sdim *string_buf_ptr++ = *yptr++; 155296417Sdim } 156296417Sdim<STRING>\" { 157296417Sdim /* All done */ 158296417Sdim BEGIN INITIAL; 159296417Sdim *string_buf_ptr = '\0'; 160296417Sdim yylval.str = string_buf; 161296417Sdim return T_STRING; 162296417Sdim } 163296417Sdim{SPACE} ; 164296417Sdim 165296417Sdim /* Register/SCB/SRAM definition keywords */ 166296417Sdimexport { return T_EXPORT; } 167296417Sdimregister { return T_REGISTER; } 168296417Sdimconst { yylval.value = FALSE; return T_CONST; } 169296417Sdimdownload { return T_DOWNLOAD; } 170296417Sdimaddress { return T_ADDRESS; } 171296417Sdimaccess_mode { return T_ACCESS_MODE; } 172296417Sdimmodes { return T_MODES; } 173296417SdimRW|RO|WO { 174296417Sdim if (strcmp(yytext, "RW") == 0) 175296417Sdim yylval.value = RW; 176296417Sdim else if (strcmp(yytext, "RO") == 0) 177296417Sdim yylval.value = RO; 178296417Sdim else 179296417Sdim yylval.value = WO; 180296417Sdim return T_MODE; 181296417Sdim } 182296417SdimBEGIN_CRITICAL { return T_BEGIN_CS; } 183END_CRITICAL { return T_END_CS; } 184SET_SRC_MODE { return T_SET_SRC_MODE; } 185SET_DST_MODE { return T_SET_DST_MODE; } 186field { return T_FIELD; } 187enum { return T_ENUM; } 188mask { return T_MASK; } 189alias { return T_ALIAS; } 190size { return T_SIZE; } 191scb { return T_SCB; } 192scratch_ram { return T_SRAM; } 193accumulator { return T_ACCUM; } 194mode_pointer { return T_MODE_PTR; } 195allones { return T_ALLONES; } 196allzeros { return T_ALLZEROS; } 197none { return T_NONE; } 198sindex { return T_SINDEX; } 199A { return T_A; } 200 201 /* Opcodes */ 202shl { return T_SHL; } 203shr { return T_SHR; } 204ror { return T_ROR; } 205rol { return T_ROL; } 206mvi { return T_MVI; } 207mov { return T_MOV; } 208clr { return T_CLR; } 209jmp { return T_JMP; } 210jc { return T_JC; } 211jnc { return T_JNC; } 212je { return T_JE; } 213jne { return T_JNE; } 214jz { return T_JZ; } 215jnz { return T_JNZ; } 216call { return T_CALL; } 217add { return T_ADD; } 218adc { return T_ADC; } 219bmov { return T_BMOV; } 220inc { return T_INC; } 221dec { return T_DEC; } 222stc { return T_STC; } 223clc { return T_CLC; } 224cmp { return T_CMP; } 225not { return T_NOT; } 226xor { return T_XOR; } 227test { return T_TEST;} 228and { return T_AND; } 229or { return T_OR; } 230ret { return T_RET; } 231nop { return T_NOP; } 232else { return T_ELSE; } 233 234 /* Allowed Symbols */ 235\<\< { return T_EXPR_LSHIFT; } 236\>\> { return T_EXPR_RSHIFT; } 237[-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; } 238 239 /* Number processing */ 2400[0-7]* { 241 yylval.value = strtol(yytext, NULL, 8); 242 return T_NUMBER; 243 } 244 2450[xX][0-9a-fA-F]+ { 246 yylval.value = strtoul(yytext + 2, NULL, 16); 247 return T_NUMBER; 248 } 249 250[1-9][0-9]* { 251 yylval.value = strtol(yytext, NULL, 10); 252 return T_NUMBER; 253 } 254 /* Include Files */ 255#include{SPACE} { 256 BEGIN INCLUDE; 257 quote_count = 0; 258 return T_INCLUDE; 259 } 260<INCLUDE>[<] { return yytext[0]; } 261<INCLUDE>[>] { BEGIN INITIAL; return yytext[0]; } 262<INCLUDE>[\"] { 263 if (quote_count != 0) 264 BEGIN INITIAL; 265 quote_count++; 266 return yytext[0]; 267 } 268<INCLUDE>{PATH} { 269 char *yptr; 270 271 yptr = yytext; 272 string_buf_ptr = string_buf; 273 while (*yptr) 274 *string_buf_ptr++ = *yptr++; 275 yylval.str = string_buf; 276 *string_buf_ptr = '\0'; 277 return T_PATH; 278 } 279<INCLUDE>. { stop("Invalid include line", EX_DATAERR); } 280#define{SPACE} { 281 BEGIN MACRODEF; 282 return T_DEFINE; 283 } 284<MACRODEF>{WORD}{SPACE} { 285 char *yptr; 286 287 /* Strip space and return as a normal symbol */ 288 yptr = yytext; 289 while (*yptr != ' ' && *yptr != '\t') 290 yptr++; 291 *yptr = '\0'; 292 yylval.sym = symtable_get(yytext); 293 string_buf_ptr = string_buf; 294 BEGIN MACROBODY; 295 return T_SYMBOL; 296 } 297<MACRODEF>{WORD}\( { 298 /* 299 * We store the symbol with its opening 300 * parren so we can differentiate macros 301 * that take args from macros with the 302 * same name that do not take args as 303 * is allowed in C. 304 */ 305 BEGIN MACROARGLIST; 306 yylval.sym = symtable_get(yytext); 307 unput('('); 308 return T_SYMBOL; 309 } 310<MACROARGLIST>{WORD} { 311 yylval.str = yytext; 312 return T_ARG; 313 } 314<MACROARGLIST>{SPACE} ; 315<MACROARGLIST>[(,] { 316 return yytext[0]; 317 } 318<MACROARGLIST>[)] { 319 string_buf_ptr = string_buf; 320 BEGIN MACROBODY; 321 return ')'; 322 } 323<MACROARGLIST>. { 324 snprintf(msgbuf, sizeof(msgbuf), "Invalid character " 325 "'%c' in macro argument list", 326 yytext[0]); 327 stop(msgbuf, EX_DATAERR); 328 } 329<MACROCALLARGS>{SPACE} ; 330<MACROCALLARGS>\( { 331 parren_count++; 332 if (parren_count == 1) 333 return ('('); 334 *string_buf_ptr++ = '('; 335 } 336<MACROCALLARGS>\) { 337 parren_count--; 338 if (parren_count == 0) { 339 BEGIN INITIAL; 340 return (')'); 341 } 342 *string_buf_ptr++ = ')'; 343 } 344<MACROCALLARGS>{MCARG} { 345 char *yptr; 346 347 yptr = yytext; 348 while (*yptr) 349 *string_buf_ptr++ = *yptr++; 350 } 351<MACROCALLARGS>\, { 352 if (string_buf_ptr != string_buf) { 353 /* 354 * Return an argument and 355 * rescan this comma so we 356 * can return it as well. 357 */ 358 *string_buf_ptr = '\0'; 359 yylval.str = string_buf; 360 string_buf_ptr = string_buf; 361 unput(','); 362 return T_ARG; 363 } 364 return ','; 365 } 366<MACROBODY>\\\n { 367 /* Eat escaped newlines. */ 368 ++yylineno; 369 } 370<MACROBODY>\r ; 371<MACROBODY>\n { 372 /* Macros end on the first unescaped newline. */ 373 BEGIN INITIAL; 374 *string_buf_ptr = '\0'; 375 yylval.str = string_buf; 376 ++yylineno; 377 return T_MACROBODY; 378 } 379<MACROBODY>{MBODY} { 380 char *yptr; 381 char c; 382 383 yptr = yytext; 384 while ((c = *yptr++)) { 385 /* 386 * Strip carriage returns. 387 */ 388 if (c == '\r') 389 continue; 390 *string_buf_ptr++ = c; 391 } 392 } 393{WORD}\( { 394 char *yptr; 395 char *ycopy; 396 397 /* May be a symbol or a macro invocation. */ 398 yylval.sym = symtable_get(yytext); 399 if (yylval.sym->type == MACRO) { 400 YY_BUFFER_STATE old_state; 401 YY_BUFFER_STATE temp_state; 402 403 ycopy = strdup(yytext); 404 yptr = ycopy + yyleng; 405 while (yptr > ycopy) 406 unput(*--yptr); 407 old_state = YY_CURRENT_BUFFER; 408 temp_state = 409 yy_create_buffer(stdin, 410 YY_BUF_SIZE); 411 yy_switch_to_buffer(temp_state); 412 mm_switch_to_buffer(old_state); 413 mmparse(); 414 mm_switch_to_buffer(temp_state); 415 yy_switch_to_buffer(old_state); 416 mm_delete_buffer(temp_state); 417 expand_macro(yylval.sym); 418 } else { 419 if (yylval.sym->type == UNINITIALIZED) { 420 /* Try without the '(' */ 421 symbol_delete(yylval.sym); 422 yytext[yyleng-1] = '\0'; 423 yylval.sym = 424 symtable_get(yytext); 425 } 426 unput('('); 427 return T_SYMBOL; 428 } 429 } 430{WORD} { 431 yylval.sym = symtable_get(yytext); 432 if (yylval.sym->type == MACRO) { 433 expand_macro(yylval.sym); 434 } else { 435 return T_SYMBOL; 436 } 437 } 438. { 439 snprintf(msgbuf, sizeof(msgbuf), "Invalid character " 440 "'%c'", yytext[0]); 441 stop(msgbuf, EX_DATAERR); 442 } 443%% 444 445typedef struct include { 446 YY_BUFFER_STATE buffer; 447 int lineno; 448 char *filename; 449 SLIST_ENTRY(include) links; 450}include_t; 451 452SLIST_HEAD(, include) include_stack; 453 454void 455include_file(char *file_name, include_type type) 456{ 457 FILE *newfile; 458 include_t *include; 459 460 newfile = NULL; 461 /* Try the current directory first */ 462 if (includes_search_curdir != 0 || type == SOURCE_FILE) 463 newfile = fopen(file_name, "r"); 464 465 if (newfile == NULL && type != SOURCE_FILE) { 466 path_entry_t include_dir; 467 for (include_dir = search_path.slh_first; 468 include_dir != NULL; 469 include_dir = include_dir->links.sle_next) { 470 char fullname[PATH_MAX]; 471 472 if ((include_dir->quoted_includes_only == TRUE) 473 && (type != QUOTED_INCLUDE)) 474 continue; 475 476 snprintf(fullname, sizeof(fullname), 477 "%s/%s", include_dir->directory, file_name); 478 479 if ((newfile = fopen(fullname, "r")) != NULL) 480 break; 481 } 482 } 483 484 if (newfile == NULL) { 485 perror(file_name); 486 stop("Unable to open input file", EX_SOFTWARE); 487 /* NOTREACHED */ 488 } 489 490 if (type != SOURCE_FILE) { 491 include = (include_t *)malloc(sizeof(include_t)); 492 if (include == NULL) { 493 stop("Unable to allocate include stack entry", 494 EX_SOFTWARE); 495 /* NOTREACHED */ 496 } 497 include->buffer = YY_CURRENT_BUFFER; 498 include->lineno = yylineno; 499 include->filename = yyfilename; 500 SLIST_INSERT_HEAD(&include_stack, include, links); 501 } 502 yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); 503 yylineno = 1; 504 yyfilename = strdup(file_name); 505} 506 507static void next_substitution(struct symbol *mac_symbol, const char *body_pos, 508 const char **next_match, 509 struct macro_arg **match_marg, regmatch_t *match); 510 511void 512expand_macro(struct symbol *macro_symbol) 513{ 514 struct macro_arg *marg; 515 struct macro_arg *match_marg; 516 const char *body_head; 517 const char *body_pos; 518 const char *next_match; 519 regmatch_t match = { .rm_so = 0, .rm_eo = 0 }; 520 521 /* 522 * Due to the nature of unput, we must work 523 * backwards through the macro body performing 524 * any expansions. 525 */ 526 body_head = macro_symbol->info.macroinfo->body; 527 body_pos = body_head + strlen(body_head); 528 while (body_pos > body_head) { 529 next_match = body_head; 530 match_marg = NULL; 531 next_substitution(macro_symbol, body_pos, &next_match, 532 &match_marg, &match); 533 534 /* Put back everything up until the replacement. */ 535 while (body_pos > next_match) 536 unput(*--body_pos); 537 538 /* Perform the replacement. */ 539 if (match_marg != NULL) { 540 const char *strp; 541 542 next_match = match_marg->replacement_text; 543 strp = next_match + strlen(next_match); 544 while (strp > next_match) 545 unput(*--strp); 546 547 /* Skip past the unexpanded macro arg. */ 548 body_pos -= match.rm_eo - match.rm_so; 549 } 550 } 551 552 /* Cleanup replacement text. */ 553 STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { 554 free(marg->replacement_text); 555 } 556} 557 558/* 559 * Find the next substitution in the macro working backwards from 560 * body_pos until the beginning of the macro buffer. next_match 561 * should be initialized to the beginning of the macro buffer prior 562 * to calling this routine. 563 */ 564static void 565next_substitution(struct symbol *mac_symbol, const char *body_pos, 566 const char **next_match, struct macro_arg **match_marg, 567 regmatch_t *match) 568{ 569 regmatch_t matches[2]; 570 struct macro_arg *marg; 571 const char *search_pos; 572 int retval; 573 574 do { 575 search_pos = *next_match; 576 577 STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) { 578 579 retval = regexec(&marg->arg_regex, search_pos, 2, 580 matches, 0); 581 if (retval == 0 582 && (matches[1].rm_eo + search_pos) <= body_pos 583 && (matches[1].rm_eo + search_pos) > *next_match) { 584 *match = matches[1]; 585 *next_match = match->rm_eo + search_pos; 586 *match_marg = marg; 587 } 588 } 589 } while (search_pos != *next_match); 590} 591 592int 593yywrap(void) 594{ 595 include_t *include; 596 597 yy_delete_buffer(YY_CURRENT_BUFFER); 598 (void)fclose(yyin); 599 if (yyfilename != NULL) 600 free(yyfilename); 601 yyfilename = NULL; 602 include = include_stack.slh_first; 603 if (include != NULL) { 604 yy_switch_to_buffer(include->buffer); 605 yylineno = include->lineno; 606 yyfilename = include->filename; 607 SLIST_REMOVE_HEAD(&include_stack, links); 608 free(include); 609 return (0); 610 } 611 return (1); 612} 613