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