1 /* In Emacs, please make this -*-c-*- mode. Thanks. */
2 
3 /*******************************************************************************
4 *
5 * McStas, neutron ray-tracing package
6 *         Copyright (C) 1997-2007, All rights reserved
7 *         Risoe National Laboratory, Roskilde, Denmark
8 *         Institut Laue Langevin, Grenoble, France
9 *
10 * Kernel: instrument.l
11 *
12 * %Identification
13 * Written by: K.N.
14 * Date: Jul  1, 1997
15 * Origin: Risoe
16 * Release: McStas 1.6
17 * Version: $Revision$
18 *
19 * Flex scanner for instrument definition files.
20 *
21 *******************************************************************************/
22 
23 
24 /* Definition section. */
25 
26 /* Do not use the `yywrap feature' - only scan a single file (see Flex manual). */
27 %option noyywrap
28 
29 
30 %{
31 #include <string.h>
32 #include <math.h>
33 #include <stdio.h>
34 
35 #include "mccode.h"
36 #include "instrument.tab.h"
37 
38 /* Fix things for bison option %pure_parser. */
39 #define YY_DECL int yylex(YYSTYPE *yylvalp)
40 #define yylval (*yylvalp)
41 
42 
43 /* Structure to hold the state of a file being parsed. */
44 struct file_state
45   {
46     YY_BUFFER_STATE buffer;
47     char *filename;
48     char *switch_line;
49     int line;
50     int oldstate;   /* Saved lexer start condition. */
51     int visible_eof;    /* If true, tell parser about end-of-file. */
52   };
53 
54 #define MAX_INCLUDE 256
55 static struct file_state file_stack[MAX_INCLUDE + 1];
56 static int file_stack_ptr = 0;
57 static char *switch_line = NULL;
58 
59 static void push_include(char *name);
60 
61 %}
62 
63 
64 /* Lexer states. */
65 
66 /* The state ccomment is used for scanning c-style comments. The state ccode
67    is used when scanning embedded C code blocks. */
68 %x ccomment
69 %x ccode
70 
71 /* The state initial_token is only used to output an initial token to
72    discriminate between parsing general instrument definitions and autoloaded
73    component definitions. */
74 %x initial_token
75 
76 /* Get file name in %include. */
77 %x inclname
78 
79 /* Get full %include line within C code blocks. */
80 %x cfullincl
81 
82 /* Get file name in %include within C code blocks. */
83 %x cinclname
84 
85 
86 /* Abbreviations. */
87 DIGIT   [0-9]
88 ALPHA   [A-Za-z]
89 ALPHANUM  {ALPHA}|{DIGIT}|"_"
90 
91 NUMBER    -?({DIGIT}*".")?{DIGIT}+([Ee][+-]?{DIGIT}+)?
92 ID    {DIGIT}*{ALPHA}{ALPHANUM}*
93 EOL             (\r\n|\n|\r)
94 INCLUDE "%include"
95 
96 %%
97 
98  /* Initially, output a single token to the parser to tell it whether to parse
99     general instrument definitions or autoloaded component definitions. */
100 <initial_token>.|\n |
101 <initial_token><<EOF>> {
102       yyless(0);
103       BEGIN(INITIAL);
104       return parse_restricted ? TOK_RESTRICTED : TOK_GENERAL;
105     }
106 
107 ABSOLUTE      return TOK_ABSOLUTE;
108 AT            return TOK_AT;
109 COMPONENT     return TOK_COMPONENT;
110 DECLARE       return TOK_DECLARE;
111 DEFINE        return TOK_DEFINE;
112 DEFINITION    return TOK_DEFINITION;
113 END           return TOK_END;
114 MCDISPLAY     return TOK_MCDISPLAY;
115 FINALLY       return TOK_FINALLY;
116 INITIALIZE    return TOK_INITIALIZE;
117 INSTRUMENT    return TOK_INSTRUMENT;
118 OUTPUT        return TOK_OUTPUT;
119 PARAMETERS    return TOK_PARAMETERS;
120 RELATIVE      return TOK_RELATIVE;
121 ROTATED       return TOK_ROTATED;
122 PREVIOUS      return TOK_PREVIOUS;
123 SETTING       return TOK_SETTING;
124 TRACE         return TOK_TRACE;
125 SHARE         return TOK_SHARE;
126 EXTEND        return TOK_EXTEND;
127 GROUP         return TOK_GROUP;         /* extended McStas grammar */
128 SAVE          return TOK_SAVE;
129 JUMP          return TOK_JUMP;          /* extended McStas grammar */
130 WHEN          return TOK_WHEN;          /* extended McStas grammar */
131 NEXT          return TOK_NEXT;          /* extended McStas grammar */
132 ITERATE       return TOK_ITERATE;       /* extended McStas grammar */
133 MYSELF        return TOK_MYSELF;        /* extended McStas grammar */
134 COPY          return TOK_COPY;          /* extended McStas grammar */
135 SPLIT         return TOK_SPLIT;         /* extended McStas grammar */
136 REMOVABLE     return TOK_REMOVABLE;     /* extended McStas grammar with include */
137 
138 "("|")"|"["|"]"|"{"|"}"|"," return yytext[0]; /* Punctuation. */
139 "="|"*"       return yytext[0]; /* Operator. */
140 
141 {NUMBER}  yylval.number = str_dup(yytext); return TOK_NUMBER;
142  /* Note: Since ID overlaps with NUMBER (eg. "2E3"), ID must come
143     after NUMBER */
144 {ID}    yylval.string = str_dup(yytext); return TOK_ID;
145 
146  /* Scanning all other C tokens used in expressions for component
147  * actual parameters.
148  * IMPORTANT!: Whenever a token is removed from here to make an independent
149  * separate token, the new token must be added to the parser rules for
150  * genatexp/topatexp.
151  */
152 "->"|"."|"!"|"~"|"++"|"--"|"+"|"-"|"&"|"sizeof"|"*"|"/"|"%"|"+"|"-"|"<<"|">>"|"<"|"<="|">"|">="|"=="|"!="|"^"|"|"|"&&"|"||"|"?"|":"|"+="|"-="|"*="|"/="|"%="|"&="|"^="|"|="|"<<="|">>=" {
153       yylval.string = str_dup(yytext);
154       return TOK_CTOK;
155 \
156     }
157 
158   /* Scanning embedded C code. */
159 
160 "%""{"[\t ]*{EOL} {
161       yylval.linenum = instr_current_line;
162       instr_current_line++;
163       BEGIN(ccode);
164       return TOK_CODE_START;
165     }
166 "%""{"[^\n]*{EOL} {
167       instr_current_line++;
168       print_error("%%{ token not on a line by itself "
169                   "on line %d of file '%s': %s.\n",
170               instr_current_line, instr_current_filename, yytext);
171       return TOK_INVALID;
172     }
173 
174 <ccode>{
175     /* normal %} symbol to end C code block */
176     [\t ]*"%""}"[\t ]*{EOL} instr_current_line++; BEGIN(INITIAL); return TOK_CODE_END;
177     /* %} symbol surrounded by some unrelevant stuff */
178     [^\n]*"%""}"[^\n]*{EOL} {
179         instr_current_line++;
180         print_warn(NULL, "%%} terminator not on a line by itself "
181                     "on line %d of file '%s': %s.\n",
182               instr_current_line, instr_current_filename, yytext);
183       }
184     /* %include full line -> jump to cfullincl state */
185     [\t ]*{INCLUDE}[^\n]*{EOL} {
186       yyless(0);  /* re-use the current line, but within cfullincl state */
187       BEGIN(cfullincl);
188       }
189     /* full line as C code */
190     [^\n]*{EOL}   {
191         instr_current_line++;
192         yylval.string = str_dup(yytext);
193         return TOK_CODE_LINE;
194       }
195     } /* end ccode */
196 
197  /* Quoted strings. Simple version: no escape sequences. */
198 \"[^\"\n\\]*\"    {
199         yylval.string =
200           str_dup_n(&yytext[1], strlen(yytext) - 2);
201         return TOK_STRING;
202       }
203  /* Quoted strings with escape sequence (e.g Win32 path): preserve all chars */
204 \"[^\"\n]*\\[^\"\n]*\"  {
205         yylval.string = str_dup_n(&yytext[1], strlen(yytext) - 2);
206         return TOK_STRING;
207       }
208 \"[^\n\"]*{EOL}   {
209         print_error("Error: Unterminated string "
210                     "on line %d of file '%s': %s.\n",
211               instr_current_line, instr_current_filename, yytext);
212       }
213 
214  /* %-style comments - ignore everything to end of line. */
215 "%"{EOL}    instr_current_line++; /* Ignore comment. */
216 "% "[^\n]*{EOL} instr_current_line++; /* Ignore comment. */
217 
218  /* Include files for McStas comp/instr (INITIAL state). */
219  /* then next token is the file name */
220 {INCLUDE}[ \t]+\" BEGIN(inclname);
221 <inclname>{
222   /* name ends with a quote char -> include as INITIAL state */
223   [^\"\n]+\" {
224         yytext[yyleng - 1] = '\0';
225         BEGIN(INITIAL);
226         if (verbose) fprintf(stderr, "Embedding %s\n", yytext);
227         push_include(yytext);
228       }
229   /* name contains char, including quote and \n -> not valid */
230   [\"\n].*  {
231         print_error("Error in %%include statement "
232                     "on line %d of file '%s': %s.\n",
233               instr_current_line, instr_current_filename, yytext);
234         BEGIN(INITIAL);
235       }
236   } /* end inclname */
237  /* Include files within C code blocks (ccode state)*/
238  /* next token is full line, regenerated by yyless(0) */
239 <cfullincl>{INCLUDE}[ \t]+\"  BEGIN(cinclname);
240 <cinclname>{
241   /* name ends with a quote char, with extension -> include as ccode state */
242   [^\"\n]+\.+.\"  {
243         yytext[yyleng - 1] = '\0';
244         BEGIN(ccode);
245         if (verbose) fprintf(stderr, "Embedding file      %s\n", yytext);
246         push_include(yytext);
247       }
248   /* name ends with a quote char, but no ext -> include as ccode state
249    * this occurs when importing a library .h/.c The .c is only included
250    * when instr->runtime option is true
251    */
252   [^\"\n]+\"  {
253         char *tmp0, *tmp1;
254         yytext[yyleng - 1] = '\0';
255         tmp0 = str_dup(yytext);
256         if (!symtab_lookup(lib_instances, tmp0))
257         {
258           tmp1 = str_cat(tmp0, ".h", NULL);
259           if (instrument_definition->include_runtime)
260           {
261             switch_line = str_cat(tmp0, ".c", NULL);
262           }
263           else
264             fprintf(stderr,"Dependency: %s.o\n", tmp0);
265 
266           BEGIN(ccode);
267           if (verbose) fprintf(stderr, "Embedding library   %s\n", tmp1);
268 
269           push_include(tmp1);
270           symtab_add(lib_instances, tmp0, NULL);
271           str_free(tmp1);
272         }
273         else
274         {
275           BEGIN(ccode);
276           instr_current_line++;  /* library was previously embedded */
277         }
278         str_free(tmp0);
279       }
280   /* name contains char, including quote and \n -> not valid */
281   [\"\n].*  {
282         print_error("Error in %%include statement "
283                     "on line %d of file '%s': %s.\n",
284               instr_current_line, instr_current_filename, yytext);
285         BEGIN(ccode);
286       }
287   } /* end  cinclname */
288 
289  /* C++ "//"-style comments - ignore everything to end of line. */
290 "//"[^\n]*{EOL} instr_current_line++; /* Ignore comment. */
291 
292  /* C-style comments. */
293 "/*"    BEGIN(ccomment);
294 <ccomment>{
295  [^*\n]*  /* Ignore comment. */
296  [^*\n]*{EOL} instr_current_line++; /* Ignore comment. */
297  "*"+[^*/\n]* /* Ignore comment. */
298  "*"+[^*/\n]*{EOL}  instr_current_line++; /* Ignore comment. */
299  "*"+"/"  BEGIN(INITIAL); /* End of comment. */
300 }
301 
302 [ \t]+      /* Ignore whitespace. */
303 [ \t]*{EOL}   instr_current_line++; /* Ignore whitespace. */
304 
305 <INITIAL,ccode><<EOF>> {
306       if(file_stack_ptr <= 0)
307       {
308         /* EOF on main instrument file. */
309         yyterminate();
310       }
311       else
312       {
313         --file_stack_ptr;
314         yy_delete_buffer(YY_CURRENT_BUFFER);
315         yy_switch_to_buffer(file_stack[file_stack_ptr].buffer);
316         instr_current_filename = file_stack[file_stack_ptr].filename;
317         instr_current_line = file_stack[file_stack_ptr].line;
318         switch_line        = file_stack[file_stack_ptr].switch_line;
319         if (switch_line)
320         {
321           char *tmp0;
322           tmp0 = str_dup(switch_line);
323           str_free(switch_line);
324           switch_line = NULL;
325           BEGIN(ccode);
326           if (verbose) fprintf(stderr, "Embedding library   %s\n", tmp0);
327           push_include(tmp0);
328           str_free(tmp0);
329         }
330         else
331         {
332           BEGIN(file_stack[file_stack_ptr].oldstate);
333           if(file_stack[file_stack_ptr].visible_eof)
334             yyterminate();
335         }
336 
337       }
338     }
339 
340 .               {
341       print_error("Invalid character `%s' "
342                   "on line %d of file '%s'.\n",
343             yytext, instr_current_line, instr_current_filename);
344       return TOK_INVALID;
345     }
346 
347 
348 
349 %%
350 
351 /* User code section. */
352 
353 /* This flag is set when autoloading component definitions to make the lexer
354    output the special initial token to switch the parser to restricted
355    mode. */
356 int parse_restricted = FALSE;
357 
358 /* Prepare to run lexical analysis on new file. */
359 void
lex_new_file(FILE * file)360 lex_new_file(FILE *file)
361 {
362   parse_restricted = FALSE;
363   BEGIN(initial_token);
364   yyrestart(file);
365 }
366 
367 
368 /* This handles the details of switching the lexer to a new file. */
369 static void
push_file(FILE * file,int restricted,int visible_eof)370 push_file(FILE *file, int restricted, int visible_eof)
371 {
372   if(file_stack_ptr >= MAX_INCLUDE)
373     fatal_error("Too deeply nested includes "
374                 "on line %d of file '%s'.\n",
375               instr_current_line, instr_current_filename);
376   file_stack[file_stack_ptr].buffer = YY_CURRENT_BUFFER;
377   file_stack[file_stack_ptr].filename = instr_current_filename;
378   file_stack[file_stack_ptr].line = instr_current_line;
379   file_stack[file_stack_ptr].oldstate = YY_START;
380   file_stack[file_stack_ptr].visible_eof = visible_eof;
381   file_stack[file_stack_ptr].switch_line = switch_line;
382   file_stack_ptr++;
383 
384   instr_current_line = 1;
385 
386   yy_switch_to_buffer(yy_create_buffer(file, YY_BUF_SIZE));
387   parse_restricted = restricted;
388 }
389 
390 /* Handle a new %include file. */
391 void
push_include(char * name)392 push_include(char *name)
393 {
394   FILE *file;
395 
396   file = open_file_search(name);
397   if(file == NULL)
398     fatal_error("Cannot open include file '%s' "
399                 "on line %d of file '%s'.\n",
400               name, instr_current_line, instr_current_filename);
401   push_file(file, FALSE, FALSE);
402   instr_current_filename = name;
403   instr_current_line = 1;
404 }
405 
406 /* Handle a new autoincluded file (uses recursive parser call). */
407 void
push_autoload(FILE * file)408 push_autoload(FILE *file)
409 {
410   push_file(file, TRUE, TRUE);
411   BEGIN(initial_token);
412 }
413 
414