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