/* In Emacs, please make this -*-c-*- mode. Thanks. */
/*******************************************************************************
*
* McStas, neutron ray-tracing package
* Copyright 1997-2002, All rights reserved
* Risoe National Laboratory, Roskilde, Denmark
* Institut Laue Langevin, Grenoble, France
*
* Kernel: instrument.l
*
* %Identification
* Written by: K.N.
* Date: Jul 1, 1997
* Origin: Risoe
* Release: McStas 1.6
* Version: 1.22
*
* Flex scanner for instrument definition files.
*
* $Id: instrument.l,v 1.37 2005/10/21 10:07:42 farhi Exp $
*
* $Log: instrument.l,v $
* Revision 1.37 2005/10/21 10:07:42 farhi
* Restrict parsing to 'normal' chars. Scandinavian stuff removed as some LeX do not support that
*
* Revision 1.36 2005/06/30 14:05:46 farhi
* Now supports \n and \r\n end of lines
*
* Revision 1.35 2004/11/19 16:22:09 farhi
* kernel (parser) now supports escape sequences in comp/instr parameters
* e.g. in Win32 pathes... (reported by R. Peacock, ILL)
*
* Revision 1.34 2003/10/06 15:02:43 farhi
* Added PREVIOUS and PREVIOUS(index) keyword for component reference.
* Works with RELATIVE keyword. index is the index backward and
* PREVIOUS is equivalent to PREVIOUS(1)
*
* Revision 1.33 2003/02/11 12:28:45 farhi
* Variouxs bug fixes after tests in the lib directory
* mcstas_r : disable output with --no-out.. flag. Fix 1D McStas output
* read_table:corrected MC_SYS_DIR -> MCSTAS define
* monitor_nd-lib: fix Log(signal) log(coord)
* HOPG.trm: reduce 4000 points -> 400 which is enough and faster to resample
* Progress_bar: precent -> percent parameter
* CS: ----------------------------------------------------------------------
*
* Revision 1.22 2002/08/29 16:39:42 ef
* enables %include in C code, embeding .h/.c from mcstas/lib
* embed only once for libraries (.h+.c)
*
* Revision 1.21 2001/09/24 10:00:00 ef
* Added GROUP, EXTEND and SHARE tokens (for McStas 1.6)
*
* Revision 1.20 2000/07/27 09:06:42 kn
* Added the extra tokens necessary to support full C expressions in
* component actual parameters.
*
* Revision 1.19 2000/07/06 12:27:11 kn
* Implement first NXDICT code (still incomplete).
*
* Revision 1.18 2000/02/15 07:42:32 kn
* Handle instrument parameters with different types (double, int, string).
*
* Revision 1.17 1999/03/18 07:31:46 kn
* Handle polarised neutrons.
*
* Revision 1.16 1999/01/28 07:54:44 kn
* Added MCDISPLAY keyword.
*
* Revision 1.15 1998/11/26 08:45:13 kn
* Fix bug with parse_restricted being defined static in this file, but
* declared extern in header file.
*
* Revision 1.14 1998/10/02 08:36:34 kn
* Added output parameters for components.
* Fixed header comment.
*
* Revision 1.13 1998/10/01 11:44:47 kn
* Added support for string expressions.
*
* Revision 1.12 1998/10/01 08:09:49 kn
* Use the search path for %include files.
*
* Revision 1.11 1998/09/23 13:58:47 kn
* Added C++ style ("//") comments.
*
* Revision 1.10 1998/08/26 12:43:21 kn
* Merged in the functionality from component.l.
* Added %include facility.
*
* Revision 1.9 1998/05/13 13:03:29 kn
* Now really fix the number syntax problem.
*
* Revision 1.9 1998/05/13 13:02:35 kn
* Now really fix the number syntax problem.
*
* Revision 1.8 1998/05/04 08:14:32 kn
* Fix problem in number syntax.
*
* Revision 1.7 1998/03/16 08:35:31 kn
* Fixed missing yylval type qualifications.
*
* Revision 1.6 1997/09/07 20:16:03 kn
* Added FINALLY construct.
*
* Revision 1.5 1997/09/07 17:57:40 kn
* Snapshot with (untested) code generation complete.
*
* Revision 1.4 1997/08/13 09:14:48 kn
* First version to properly parse instrument definition files.
*
* Revision 1.3 1997/07/02 07:27:32 kn
* Misc. cleanup.
*
* Revision 1.2 1997/07/01 08:26:21 kn
* Fixed problem when scanning identifiers: now returns a persistent copy
* of the name.
*
*******************************************************************************/
/* Definition section. */
/* Do not use the `yywrap feature' - only scan a single file (see Flex manual). */
%option noyywrap
%{
#include <string.h>
#include <math.h>
#include <stdio.h>
#include "mcstas.h"
#include "instrument.tab.h"
/* Fix things for bison option %pure_parser. */
#define YY_DECL int yylex(YYSTYPE *yylvalp)
#define yylval (*yylvalp)
/* Structure to hold the state of a file being parsed. */
struct file_state
{
YY_BUFFER_STATE buffer;
char *filename;
char *switch_line;
int line;
int oldstate; /* Saved lexer start condition. */
int visible_eof; /* If true, tell parser about end-of-file. */
};
#define MAX_INCLUDE 256
static struct file_state file_stack[MAX_INCLUDE + 1];
static int file_stack_ptr = 0;
static char *switch_line = NULL;
static void push_include(char *name);
%}
/* Lexer states. */
/* The state ccomment is used for scanning c-style comments. The state ccode
is used when scanning embedded C code blocks. */
%x ccomment
%x ccode
/* The state initial_token is only used to output an initial token to
discriminate between parsing general instrument definitions and autoloaded
component definitions. */
%x initial_token
/* Get file name in %include. */
%x inclname
/* Get full %include line within C code blocks. */
%x cfullincl
/* Get file name in %include within C code blocks. */
%x cinclname
/* Abbreviations. */
DIGIT [0-9]
ALPHA [A-Za-z]
ALPHANUM {ALPHA}|{DIGIT}|"_"
NUMBER -?({DIGIT}*".")?{DIGIT}+([Ee][+-]?{DIGIT}+)?
ID {DIGIT}*{ALPHA}{ALPHANUM}*
EOL (\r\n|\n|\r)
INCLUDE "%include"
%%
/* Initially, output a single token to the parser to tell it whether to parse
general instrument definitions or autoloaded component definitions. */
<initial_token>.|\n |
<initial_token><<EOF>> {
yyless(0);
BEGIN(INITIAL);
return parse_restricted ? TOK_RESTRICTED : TOK_GENERAL;
}
ABSOLUTE return TOK_ABSOLUTE;
AT return TOK_AT;
COMPONENT return TOK_COMPONENT;
DECLARE return TOK_DECLARE;
DEFINE return TOK_DEFINE;
DEFINITION return TOK_DEFINITION;
END return TOK_END;
MCDISPLAY return TOK_MCDISPLAY;
FINALLY return TOK_FINALLY;
EXTERN return TOK_EXTERN;
INITIALIZE return TOK_INITIALIZE;
INSTRUMENT return TOK_INSTRUMENT;
OUTPUT return TOK_OUTPUT;
PARAMETERS return TOK_PARAMETERS;
POLARISATION return TOK_POLARISATION;
RELATIVE return TOK_RELATIVE;
ROTATED return TOK_ROTATED;
PREVIOUS return TOK_PREVIOUS;
SETTING return TOK_SETTING;
STATE return TOK_STATE;
TRACE return TOK_TRACE;
SHARE return TOK_SHARE; /* ADD: E. Farhi Sep 20th, 2001 */
EXTEND return TOK_EXTEND; /* ADD: E. Farhi Sep 20th, 2001 */
GROUP return TOK_GROUP; /* ADD: E. Farhi Sep 24th, 2001 */
NEXUS return TOK_NEXUS; /* ADD: E. Farhi Aug 6th, 2002 */
DICTFILE return TOK_DICTFILE; /* ADD: E. Farhi Aug 6th, 2002 */
HDF return TOK_HDF; /* ADD: E. Farhi Aug 6th, 2002 */
SAVE return TOK_SAVE; /* ADD: E. Farhi Aug 25th, 2002 */
"("|")"|"["|"]"|"{"|"}"|"," return yytext[0]; /* Punctuation. */
"="|"*" return yytext[0]; /* Operator. */
{NUMBER} yylval.number = str_dup(yytext); return TOK_NUMBER;
/* Note: Since ID overlaps with NUMBER (eg. "2E3"), ID must come
after NUMBER */
{ID} yylval.string = str_dup(yytext); return TOK_ID;
/* Scanning all other C tokens used in expressions for component
* actual parameters.
* IMPORTANT!: Whenever a token is removed from here to make an independent
* separate token, the new token must be added to the parser rules for
* genatexp/topatexp.
*/
"->"|"."|"!"|"~"|"++"|"--"|"+"|"-"|"&"|"sizeof"|"*"|"/"|"%"|"+"|"-"|"<<"|">>"|"<"|"<="|">"|">="|"=="|"!="|"^"|"|"|"&&"|"||"|"?"|":"|"+="|"-="|"*="|"/="|"%="|"&="|"^="|"|="|"<<="|">>=" {
yylval.string = str_dup(yytext);
return TOK_CTOK;
\
}
/* Scanning embedded C code. */
"%""{"[\t ]*{EOL} {
yylval.linenum = instr_current_line;
instr_current_line++;
BEGIN(ccode);
return TOK_CODE_START;
}
"%""{"[^\n]*{EOL} {
instr_current_line++;
print_error("%%{ token not on a line by itself "
"on line %d of file '%s': %s.\n",
instr_current_line, instr_current_filename, yytext);
return TOK_INVALID;
}
<ccode>{
/* normal %} symbol to end C code block */
[\t ]*"%""}"[\t ]*{EOL} instr_current_line++; BEGIN(INITIAL); return TOK_CODE_END;
/* %} symbol surrounded by some unrelevant stuff */
[^\n]*"%""}"[^\n]*{EOL} {
instr_current_line++;
print_warn(NULL, "%%} terminator not on a line by itself "
"on line %d of file '%s': %s.\n",
instr_current_line, instr_current_filename, yytext);
}
/* %include full line -> jump to cfullincl state */
[\t ]*{INCLUDE}[^\n]*{EOL} {
yyless(0); /* re-use the current line, but within cfullincl state */
BEGIN(cfullincl);
}
/* full line as C code */
[^\n]*{EOL} {
instr_current_line++;
yylval.string = str_dup(yytext);
return TOK_CODE_LINE;
}
} /* end ccode */
/* Quoted strings. Simple version: no escape sequences. */
\"[^\"\n\\]*\" {
yylval.string =
str_dup_n(&yytext[1], strlen(yytext) - 2);
return TOK_STRING;
}
/* Quoted strings with escape sequence (e.g Win32 path): preserve all chars */
\"[^\"\n]*\\[^\"\n]*\" {
yylval.string = str_dup_n(&yytext[1], strlen(yytext) - 2);
return TOK_STRING;
}
\"[^\n\"]*{EOL} {
print_error("Error: Unterminated string "
"on line %d of file '%s': %s.\n",
instr_current_line, instr_current_filename, yytext);
}
/* %-style comments - ignore everything to end of line. */
"%"{EOL} instr_current_line++; /* Ignore comment. */
"% "[^\n]*{EOL} instr_current_line++; /* Ignore comment. */
/* Include files for McStas comp/instr (INITIAL state). */
/* then next token is the file name */
{INCLUDE}[ \t]+\" BEGIN(inclname);
<inclname>{
/* name ends with a quote char -> include as INITIAL state */
[^\"\n]+\" {
yytext[yyleng - 1] = '\0';
BEGIN(INITIAL);
if (verbose) fprintf(stderr, "Embedding %s\n", yytext);
push_include(yytext);
}
/* name contains char, including quote and \n -> not valid */
[\"\n].* {
print_error("Error in %%include statement "
"on line %d of file '%s': %s.\n",
instr_current_line, instr_current_filename, yytext);
BEGIN(INITIAL);
}
} /* end inclname */
/* Include files within C code blocks (ccode state)*/
/* next token is full line, regenerated by yyless(0) */
<cfullincl>{INCLUDE}[ \t]+\" BEGIN(cinclname);
<cinclname>{
/* name ends with a quote char, with extension -> include as ccode state */
[^\"\n]+\.+.\" {
yytext[yyleng - 1] = '\0';
BEGIN(ccode);
if (verbose) fprintf(stderr, "Embedding file %s\n", yytext);
push_include(yytext);
}
/* name ends with a quote char, but no ext -> include as ccode state
* this occurs when importing a library .h/.c The .c is only included
* when instr->runtime option is true
*/
[^\"\n]+\" {
char *tmp0, *tmp1;
yytext[yyleng - 1] = '\0';
tmp0 = str_dup(yytext);
if (!symtab_lookup(lib_instances, tmp0))
{
tmp1 = str_cat(tmp0, ".h", NULL);
if (instrument_definition->include_runtime)
{
switch_line = str_cat(tmp0, ".c", NULL);
}
else
fprintf(stderr,"Dependency: %s.o\n", tmp0);
BEGIN(ccode);
if (verbose) fprintf(stderr, "Embedding library %s\n", tmp1);
push_include(tmp1);
symtab_add(lib_instances, tmp0, NULL);
str_free(tmp1);
}
else
{
BEGIN(ccode);
instr_current_line++; /* library was previously embedded */
}
str_free(tmp0);
}
/* name contains char, including quote and \n -> not valid */
[\"\n].* {
print_error("Error in %%include statement "
"on line %d of file '%s': %s.\n",
instr_current_line, instr_current_filename, yytext);
BEGIN(ccode);
}
} /* end cinclname */
/* C++ "//"-style comments - ignore everything to end of line. */
"//"[^\n]*{EOL} instr_current_line++; /* Ignore comment. */
/* C-style comments. */
"/*" BEGIN(ccomment);
<ccomment>{
[^*\n]* /* Ignore comment. */
[^*\n]*{EOL} instr_current_line++; /* Ignore comment. */
"*"+[^*/\n]* /* Ignore comment. */
"*"+[^*/\n]*{EOL} instr_current_line++; /* Ignore comment. */
"*"+"/" BEGIN(INITIAL); /* End of comment. */
}
[ \t]+ /* Ignore whitespace. */
[ \t]*{EOL} instr_current_line++; /* Ignore whitespace. */
<INITIAL,ccode><<EOF>> {
if(file_stack_ptr <= 0)
{
/* EOF on main instrument file. */
yyterminate();
}
else
{
--file_stack_ptr;
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(file_stack[file_stack_ptr].buffer);
instr_current_filename = file_stack[file_stack_ptr].filename;
instr_current_line = file_stack[file_stack_ptr].line;
switch_line = file_stack[file_stack_ptr].switch_line;
if (switch_line)
{
char *tmp0;
tmp0 = str_dup(switch_line);
str_free(switch_line);
switch_line = NULL;
BEGIN(ccode);
if (verbose) fprintf(stderr, "Embedding library %s\n", tmp0);
push_include(tmp0);
str_free(tmp0);
}
else
{
BEGIN(file_stack[file_stack_ptr].oldstate);
if(file_stack[file_stack_ptr].visible_eof)
yyterminate();
}
}
}
. {
print_error("Invalid character `%s' "
"on line %d of file '%s'.\n",
yytext, instr_current_line, instr_current_filename);
return TOK_INVALID;
}
%%
/* User code section. */
/* This flag is set when autoloading component definitions to make the lexer
output the special initial token to switch the parser to restricted
mode. */
int parse_restricted = FALSE;
/* Prepare to run lexical analysis on new file. */
void
lex_new_file(FILE *file)
{
parse_restricted = FALSE;
BEGIN(initial_token);
yyrestart(file);
}
/* This handles the details of switching the lexer to a new file. */
static void
push_file(FILE *file, int restricted, int visible_eof)
{
if(file_stack_ptr >= MAX_INCLUDE)
fatal_error("Too deeply nested includes "
"on line %d of file '%s'.\n",
instr_current_line, instr_current_filename);
file_stack[file_stack_ptr].buffer = YY_CURRENT_BUFFER;
file_stack[file_stack_ptr].filename = instr_current_filename;
file_stack[file_stack_ptr].line = instr_current_line;
file_stack[file_stack_ptr].oldstate = YY_START;
file_stack[file_stack_ptr].visible_eof = visible_eof;
file_stack[file_stack_ptr].switch_line = switch_line;
file_stack_ptr++;
instr_current_line = 1;
yy_switch_to_buffer(yy_create_buffer(file, YY_BUF_SIZE));
parse_restricted = restricted;
}
/* Handle a new %include file. */
void
push_include(char *name)
{
FILE *file;
file = open_file_search(name);
if(file == NULL)
fatal_error("Cannot open include file '%s' "
"on line %d of file '%s'.\n",
name, instr_current_line, instr_current_filename);
push_file(file, FALSE, FALSE);
instr_current_filename = name;
instr_current_line = 1;
}
/* Handle a new autoincluded file (uses recursive parser call). */
void
push_autoload(FILE *file)
{
push_file(file, TRUE, TRUE);
BEGIN(initial_token);
}
syntax highlighted by Code2HTML, v. 0.9.1