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