Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / drivers / scsi / aic7xxx / aicasm / aicasm_scan.l
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$
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
66 static char string_buf[MAX_STR_CONST];
67 static char *string_buf_ptr;
68 static int  parren_count;
69 static int  quote_count;
70 static char buf[255];
71 %}
72
73 PATH            ([/]*[-A-Za-z0-9_.])+
74 WORD            [A-Za-z_][-A-Za-z_0-9]*
75 SPACE           [ \t]+
76 MCARG           [^(), \t]+
77 MBODY           ((\\[^\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; }
98 if[ \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
136 VERSION                 { return T_VERSION; }
137 PREFIX                  { return T_PREFIX; }
138 PATCH_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 */
160 export                  { return T_EXPORT; }
161 register                { return T_REGISTER; }
162 const                   { yylval.value = FALSE; return T_CONST; }
163 download                { return T_DOWNLOAD; }
164 address                 { return T_ADDRESS; }
165 access_mode             { return T_ACCESS_MODE; }
166 modes                   { return T_MODES; }
167 RW|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                         }
176 BEGIN_CRITICAL          { return T_BEGIN_CS; }
177 END_CRITICAL            { return T_END_CS; }
178 SET_SRC_MODE            { return T_SET_SRC_MODE; }
179 SET_DST_MODE            { return T_SET_DST_MODE; }
180 field                   { return T_FIELD; }
181 enum                    { return T_ENUM; }
182 mask                    { return T_MASK; }
183 alias                   { return T_ALIAS; }
184 size                    { return T_SIZE; }
185 scb                     { return T_SCB; }
186 scratch_ram             { return T_SRAM; }
187 accumulator             { return T_ACCUM; }
188 mode_pointer            { return T_MODE_PTR; }
189 allones                 { return T_ALLONES; }
190 allzeros                { return T_ALLZEROS; }
191 none                    { return T_NONE; }
192 sindex                  { return T_SINDEX; }
193 A                       { return T_A; }
194
195         /* Opcodes */
196 shl                     { return T_SHL; }
197 shr                     { return T_SHR; }
198 ror                     { return T_ROR; }
199 rol                     { return T_ROL; }
200 mvi                     { return T_MVI; }
201 mov                     { return T_MOV; }
202 clr                     { return T_CLR; }
203 jmp                     { return T_JMP; }
204 jc                      { return T_JC;  }
205 jnc                     { return T_JNC; }
206 je                      { return T_JE;  }
207 jne                     { return T_JNE; }
208 jz                      { return T_JZ;  }
209 jnz                     { return T_JNZ; }
210 call                    { return T_CALL; }
211 add                     { return T_ADD; }
212 adc                     { return T_ADC; }
213 bmov                    { return T_BMOV; }
214 inc                     { return T_INC; }
215 dec                     { return T_DEC; }
216 stc                     { return T_STC; }
217 clc                     { return T_CLC; }
218 cmp                     { return T_CMP; }
219 not                     { return T_NOT; }
220 xor                     { return T_XOR; }
221 test                    { return T_TEST;}
222 and                     { return T_AND; }
223 or                      { return T_OR;  }
224 ret                     { return T_RET; }
225 nop                     { return T_NOP; }
226 else                    { 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 */
234 0[0-7]*                 {
235                                 yylval.value = strtol(yytext, NULL, 8);
236                                 return T_NUMBER;
237                         }
238
239 0[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
439 typedef struct include {
440         YY_BUFFER_STATE  buffer;
441         int              lineno;
442         char            *filename;
443         SLIST_ENTRY(include) links;
444 }include_t;
445
446 SLIST_HEAD(, include) include_stack;
447
448 void
449 include_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
501 static 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
505 void
506 expand_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, &macro_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  */
559 static void
560 next_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
587 int
588 yywrap()
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 }