xref: /linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l (revision 88e45067a30918ebb4942120892963e2311330af)
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#20 $
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 "../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 buf[255];
67 void mm_switch_to_buffer(YY_BUFFER_STATE);
68 void mmparse();
69 void mm_delete_buffer(YY_BUFFER_STATE);
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 \r			;
90 "/*"			{ BEGIN COMMENT;  /* Enter comment eating state */ }
91 <COMMENT>"/*"		{ fprintf(stderr, "Warning! Comment within comment."); }
92 <COMMENT>\n		{ ++yylineno; }
93 <COMMENT>[^*/\n]*	;
94 <COMMENT>"*"+[^*/\n]*	;
95 <COMMENT>"/"+[^*/\n]*	;
96 <COMMENT>"*"+"/"	{ BEGIN INITIAL; }
97 if[ \t]*\(		{
98 				string_buf_ptr = string_buf;
99 				parren_count = 1;
100 				BEGIN CEXPR;
101 				return T_IF;
102 			}
103 <CEXPR>\(		{	*string_buf_ptr++ = '('; parren_count++; }
104 <CEXPR>\)		{
105 				parren_count--;
106 				if (parren_count == 0) {
107 					/* All done */
108 					BEGIN INITIAL;
109 					*string_buf_ptr = '\0';
110 					yylval.sym = symtable_get(string_buf);
111 					return T_CEXPR;
112 				} else {
113 					*string_buf_ptr++ = ')';
114 				}
115 			}
116 <CEXPR>\n		{ ++yylineno; }
117 <CEXPR>\r		;
118 <CEXPR>[^()\n]+	{
119 				char *yptr;
120 
121 				yptr = yytext;
122 				while (*yptr != '\0') {
123 					/* Remove duplicate spaces */
124 					if (*yptr == '\t')
125 						*yptr = ' ';
126 					if (*yptr == ' '
127 					 && string_buf_ptr != string_buf
128 					 && string_buf_ptr[-1] == ' ')
129 						yptr++;
130 					else
131 						*string_buf_ptr++ = *yptr++;
132 				}
133 			}
134 else			{ return T_ELSE; }
135 VERSION			{ return T_VERSION; }
136 PREFIX			{ return T_PREFIX; }
137 PATCH_ARG_LIST		{ return T_PATCH_ARG_LIST; }
138 \"			{
139 				string_buf_ptr = string_buf;
140 				BEGIN STRING;
141 			}
142 <STRING>[^"]+		{
143 				char *yptr;
144 
145 				yptr = yytext;
146 				while (*yptr)
147 					*string_buf_ptr++ = *yptr++;
148 			}
149 <STRING>\"		{
150 				/* All done */
151 				BEGIN INITIAL;
152 				*string_buf_ptr = '\0';
153 				yylval.str = string_buf;
154 				return T_STRING;
155 			}
156 {SPACE}			 ;
157 
158 	/* Register/SCB/SRAM definition keywords */
159 export			{ return T_EXPORT; }
160 register		{ return T_REGISTER; }
161 const			{ yylval.value = FALSE; return T_CONST; }
162 download		{ return T_DOWNLOAD; }
163 address			{ return T_ADDRESS; }
164 count			{ return T_COUNT; }
165 access_mode		{ return T_ACCESS_MODE; }
166 dont_generate_debug_code { return T_DONT_GENERATE_DEBUG_CODE; }
167 modes			{ return T_MODES; }
168 RW|RO|WO		{
169 				 if (strcmp(yytext, "RW") == 0)
170 					yylval.value = RW;
171 				 else if (strcmp(yytext, "RO") == 0)
172 					yylval.value = RO;
173 				 else
174 					yylval.value = WO;
175 				 return T_MODE;
176 			}
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 	/* Instruction Formatting */
193 PAD_PAGE		{ return T_PAD_PAGE; }
194 BEGIN_CRITICAL		{ return T_BEGIN_CS; }
195 END_CRITICAL		{ return T_END_CS; }
196 SET_SRC_MODE		{ return T_SET_SRC_MODE; }
197 SET_DST_MODE		{ return T_SET_DST_MODE; }
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 
231 	/* ARP2 16bit extensions */
232 	/* or16			{ return T_OR16; } */
233 	/* and16			{ return T_AND16; }*/
234 	/* xor16			{ return T_XOR16; }*/
235 	/* add16			{ return T_ADD16; }*/
236 	/* adc16			{ return T_ADC16; }*/
237 	/* mvi16			{ return T_MVI16; }*/
238 	/* test16			{ return T_TEST16; }*/
239 	/* cmp16			{ return T_CMP16; }*/
240 	/* cmpxchg			{ return T_CMPXCHG; }*/
241 
242 	/* Allowed Symbols */
243 \<\<			{ return T_EXPR_LSHIFT; }
244 \>\>			{ return T_EXPR_RSHIFT; }
245 [-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; }
246 
247 	/* Number processing */
248 0[0-7]*			{
249 				yylval.value = strtol(yytext, NULL, 8);
250 				return T_NUMBER;
251 			}
252 
253 0[xX][0-9a-fA-F]+	{
254 				yylval.value = strtoul(yytext + 2, NULL, 16);
255 				return T_NUMBER;
256 			}
257 
258 [1-9][0-9]*		{
259 				yylval.value = strtol(yytext, NULL, 10);
260 				return T_NUMBER;
261 			}
262 	/* Include Files */
263 #include{SPACE}		{
264 				BEGIN INCLUDE;
265 				quote_count = 0;
266 				return T_INCLUDE;
267 			}
268 <INCLUDE>[<]		{ return yytext[0]; }
269 <INCLUDE>[>]		{ BEGIN INITIAL; return yytext[0]; }
270 <INCLUDE>[\"]		{
271 				if (quote_count != 0)
272 					BEGIN INITIAL;
273 				quote_count++;
274 				return yytext[0];
275 			}
276 <INCLUDE>{PATH}		{
277 				char *yptr;
278 
279 				yptr = yytext;
280 				string_buf_ptr = string_buf;
281 				while (*yptr)
282 					*string_buf_ptr++ = *yptr++;
283 				yylval.str = string_buf;
284 				*string_buf_ptr = '\0';
285 				return T_PATH;
286 			}
287 <INCLUDE>.		{ stop("Invalid include line", EX_DATAERR); }
288 #define{SPACE}		{
289 				BEGIN MACRODEF;
290 				return T_DEFINE;
291 			}
292 <MACRODEF>{WORD}{SPACE}	{
293 				char *yptr;
294 
295 				/* Strip space and return as a normal symbol */
296 				yptr = yytext;
297 				while (*yptr != ' ' && *yptr != '\t')
298 					yptr++;
299 				*yptr = '\0';
300 				yylval.sym = symtable_get(yytext);
301 				string_buf_ptr = string_buf;
302 				BEGIN MACROBODY;
303 				return T_SYMBOL;
304 			}
305 <MACRODEF>{WORD}\(	{
306 				/*
307 				 * We store the symbol with its opening
308 				 * parren so we can differentiate macros
309 				 * that take args from macros with the
310 				 * same name that do not take args as
311 				 * is allowed in C.
312 				 */
313 				BEGIN MACROARGLIST;
314 				yylval.sym = symtable_get(yytext);
315 				unput('(');
316 				return T_SYMBOL;
317 			}
318 <MACROARGLIST>{WORD}	{
319 				yylval.str = yytext;
320 				return T_ARG;
321 			}
322 <MACROARGLIST>{SPACE}   ;
323 <MACROARGLIST>[(,]	{
324 				return yytext[0];
325 			}
326 <MACROARGLIST>[)]	{
327 				string_buf_ptr = string_buf;
328 				BEGIN MACROBODY;
329 				return ')';
330 			}
331 <MACROARGLIST>.		{
332 				snprintf(buf, sizeof(buf), "Invalid character "
333 					 "'%c' in macro argument list",
334 					 yytext[0]);
335 				stop(buf, EX_DATAERR);
336 			}
337 <MACROCALLARGS>{SPACE}  ;
338 <MACROCALLARGS>\(	{
339 				parren_count++;
340 				if (parren_count == 1)
341 					return ('(');
342 				*string_buf_ptr++ = '(';
343 			}
344 <MACROCALLARGS>\)	{
345 				parren_count--;
346 				if (parren_count == 0) {
347 					BEGIN INITIAL;
348 					return (')');
349 				}
350 				*string_buf_ptr++ = ')';
351 			}
352 <MACROCALLARGS>{MCARG}	{
353 				char *yptr;
354 
355 				yptr = yytext;
356 				while (*yptr)
357 					*string_buf_ptr++ = *yptr++;
358 			}
359 <MACROCALLARGS>\,	{
360 				if (string_buf_ptr != string_buf) {
361 					/*
362 					 * Return an argument and
363 					 * rescan this comma so we
364 					 * can return it as well.
365 					 */
366 					*string_buf_ptr = '\0';
367 					yylval.str = string_buf;
368 					string_buf_ptr = string_buf;
369 					unput(',');
370 					return T_ARG;
371 				}
372 				return ',';
373 			}
374 <MACROBODY>\\\n		{
375 				/* Eat escaped newlines. */
376 				++yylineno;
377 			}
378 <MACROBODY>\r		;
379 <MACROBODY>\n		{
380 				/* Macros end on the first unescaped newline. */
381 				BEGIN INITIAL;
382 				*string_buf_ptr = '\0';
383 				yylval.str = string_buf;
384 				++yylineno;
385 				return T_MACROBODY;
386 			}
387 <MACROBODY>{MBODY}	{
388 				char *yptr;
389 				char c;
390 
391 				yptr = yytext;
392 				while (c = *yptr++) {
393 					/*
394 					 * Strip carriage returns.
395 					 */
396 					if (c == '\r')
397 						continue;
398 					*string_buf_ptr++ = c;
399 				}
400 			}
401 {WORD}\(		{
402 				char *yptr;
403 				char *ycopy;
404 
405 				/* May be a symbol or a macro invocation. */
406 				yylval.sym = symtable_get(yytext);
407 				if (yylval.sym->type == MACRO) {
408 					YY_BUFFER_STATE old_state;
409 					YY_BUFFER_STATE temp_state;
410 
411 					ycopy = strdup(yytext);
412 					yptr = ycopy + yyleng;
413 					while (yptr > ycopy)
414 						unput(*--yptr);
415 					old_state = YY_CURRENT_BUFFER;
416 					temp_state =
417 					    yy_create_buffer(stdin,
418 							     YY_BUF_SIZE);
419 					yy_switch_to_buffer(temp_state);
420 					mm_switch_to_buffer(old_state);
421 					mmparse();
422 					mm_switch_to_buffer(temp_state);
423 					yy_switch_to_buffer(old_state);
424 					mm_delete_buffer(temp_state);
425 					expand_macro(yylval.sym);
426 				} else {
427 					if (yylval.sym->type == UNINITIALIZED) {
428 						/* Try without the '(' */
429 						symbol_delete(yylval.sym);
430 						yytext[yyleng-1] = '\0';
431 						yylval.sym =
432 						    symtable_get(yytext);
433 					}
434 					unput('(');
435 					return T_SYMBOL;
436 				}
437 			}
438 {WORD}			{
439 				yylval.sym = symtable_get(yytext);
440 				if (yylval.sym->type == MACRO) {
441 					expand_macro(yylval.sym);
442 				} else {
443 					return T_SYMBOL;
444 				}
445 			}
446 .			{
447 				snprintf(buf, sizeof(buf), "Invalid character "
448 					 "'%c'", yytext[0]);
449 				stop(buf, EX_DATAERR);
450 			}
451 %%
452 
453 typedef struct include {
454         YY_BUFFER_STATE  buffer;
455         int              lineno;
456         char            *filename;
457 	SLIST_ENTRY(include) links;
458 }include_t;
459 
460 SLIST_HEAD(, include) include_stack;
461 
462 void
463 include_file(char *file_name, include_type type)
464 {
465 	FILE *newfile;
466 	include_t *include;
467 
468 	newfile = NULL;
469 	/* Try the current directory first */
470 	if (includes_search_curdir != 0 || type == SOURCE_FILE)
471 		newfile = fopen(file_name, "r");
472 
473 	if (newfile == NULL && type != SOURCE_FILE) {
474                 path_entry_t include_dir;
475                 for (include_dir = search_path.slh_first;
476                      include_dir != NULL;
477                      include_dir = include_dir->links.sle_next) {
478 			char fullname[PATH_MAX];
479 
480 			if ((include_dir->quoted_includes_only == TRUE)
481 			 && (type != QUOTED_INCLUDE))
482 				continue;
483 
484 			snprintf(fullname, sizeof(fullname),
485 				 "%s/%s", include_dir->directory, file_name);
486 
487 			if ((newfile = fopen(fullname, "r")) != NULL)
488 				break;
489                 }
490         }
491 
492 	if (newfile == NULL) {
493 		perror(file_name);
494 		stop("Unable to open input file", EX_SOFTWARE);
495 		/* NOTREACHED */
496 	}
497 
498 	if (type != SOURCE_FILE) {
499 		include = (include_t *)malloc(sizeof(include_t));
500 		if (include == NULL) {
501 			stop("Unable to allocate include stack entry",
502 			     EX_SOFTWARE);
503 			/* NOTREACHED */
504 		}
505 		include->buffer = YY_CURRENT_BUFFER;
506 		include->lineno = yylineno;
507 		include->filename = yyfilename;
508 		SLIST_INSERT_HEAD(&include_stack, include, links);
509 	}
510 	yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
511 	yylineno = 1;
512 	yyfilename = strdup(file_name);
513 }
514 
515 static void next_substitution(struct symbol *mac_symbol, const char *body_pos,
516 			      const char **next_match,
517 			      struct macro_arg **match_marg, regmatch_t *match);
518 
519 void
520 expand_macro(struct symbol *macro_symbol)
521 {
522 	struct macro_arg *marg;
523 	struct macro_arg *match_marg;
524 	const char *body_head;
525 	const char *body_pos;
526 	const char *next_match;
527 
528 	/*
529 	 * Due to the nature of unput, we must work
530 	 * backwards through the macro body performing
531 	 * any expansions.
532 	 */
533 	body_head = macro_symbol->info.macroinfo->body;
534 	body_pos = body_head + strlen(body_head);
535 	while (body_pos > body_head) {
536 		regmatch_t match;
537 
538 		next_match = body_head;
539 		match_marg = NULL;
540 		next_substitution(macro_symbol, body_pos, &next_match,
541 				  &match_marg, &match);
542 
543 		/* Put back everything up until the replacement. */
544 		while (body_pos > next_match)
545 			unput(*--body_pos);
546 
547 		/* Perform the replacement. */
548 		if (match_marg != NULL) {
549 			const char *strp;
550 
551 			next_match = match_marg->replacement_text;
552 			strp = next_match + strlen(next_match);
553 			while (strp > next_match)
554 				unput(*--strp);
555 
556 			/* Skip past the unexpanded macro arg. */
557 			body_pos -= match.rm_eo - match.rm_so;
558 		}
559 	}
560 
561 	/* Cleanup replacement text. */
562 	STAILQ_FOREACH(marg, &macro_symbol->info.macroinfo->args, links) {
563 		free(marg->replacement_text);
564 	}
565 }
566 
567 /*
568  * Find the next substitution in the macro working backwards from
569  * body_pos until the beginning of the macro buffer.  next_match
570  * should be initialized to the beginning of the macro buffer prior
571  * to calling this routine.
572  */
573 static void
574 next_substitution(struct symbol *mac_symbol, const char *body_pos,
575 		  const char **next_match, struct macro_arg **match_marg,
576 		  regmatch_t *match)
577 {
578 	regmatch_t	  matches[2];
579 	struct macro_arg *marg;
580 	const char	 *search_pos;
581 	int		  retval;
582 
583 	do {
584 		search_pos = *next_match;
585 
586 		STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) {
587 
588 			retval = regexec(&marg->arg_regex, search_pos, 2,
589 					 matches, 0);
590 			if (retval == 0
591 			 && (matches[1].rm_eo + search_pos) <= body_pos
592 			 && (matches[1].rm_eo + search_pos) > *next_match) {
593 				*match = matches[1];
594 				*next_match = match->rm_eo + search_pos;
595 				*match_marg = marg;
596 			}
597 		}
598 	} while (search_pos != *next_match);
599 }
600 
601 int
602 yywrap()
603 {
604 	include_t *include;
605 
606 	yy_delete_buffer(YY_CURRENT_BUFFER);
607 	(void)fclose(yyin);
608 	if (yyfilename != NULL)
609 		free(yyfilename);
610 	yyfilename = NULL;
611 	include = include_stack.slh_first;
612 	if (include != NULL) {
613 		yy_switch_to_buffer(include->buffer);
614 		yylineno = include->lineno;
615 		yyfilename = include->filename;
616 		SLIST_REMOVE_HEAD(&include_stack, links);
617 		free(include);
618 		return (0);
619 	}
620 	return (1);
621 }
622