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