/[svn]/linuxsampler/trunk/src/scriptvm/scanner.l
ViewVC logotype

Diff of /linuxsampler/trunk/src/scriptvm/scanner.l

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2581 by schoenebeck, Fri May 30 12:48:05 2014 UTC revision 3557 by schoenebeck, Sun Aug 18 00:06:04 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 2014 Christian Schoenebeck and Andreas Persson   * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson
3   *   *
4   * http://www.linuxsampler.org   * http://www.linuxsampler.org
5   *   *
# Line 7  Line 7 
7   * See README file for details.   * See README file for details.
8   */   */
9    
10  /* Token scanner for instrument script language. */  /* Token scanner for NKSP real-time instrument script language. */
   
 /* FIXME: line numbers (i.e. on error/warning messages) are incorrect, because  
    the current grammar does not process new line characters. \n is currently  
    filtered out in this lexer. Due to this, the parser will sometimes read  
    several lines before it matches the next complete grammar rule, causing the  
    incorrect lines in the error/warning messages. */  
11    
12  %{  %{
13    
# Line 26  Line 20 
20  {                                       \  {                                       \
21      yylloc->first_line = yylineno;      \      yylloc->first_line = yylineno;      \
22      yylloc->last_line  = yylineno;      \      yylloc->last_line  = yylineno;      \
23      /* first_column = TODO */           \      yylloc->first_column = yycolumn;    \
24      /* last_column  = TODO */           \      yycolumn += yyleng;                 \
25        yylloc->last_column = yycolumn - 1; \
26      /*printf("lex: line '%s'\n", yytext);*/  \      /*printf("lex: line '%s'\n", yytext);*/  \
27  }  }
28  // custom (f)lex input for reading from std::istream object  // custom (f)lex input for reading from std::istream object
# Line 43  Line 38 
38  }  }
39    
40  static void scanner_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {  static void scanner_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {
41      context->addErr(locp->first_line, err);      context->addErr(locp->first_line, locp->last_line, locp->first_column, locp->last_column, err);
42  }  }
43    
44  static void scanner_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {  static void scanner_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {
45      context->addWrn(locp->first_line, txt);      context->addWrn(locp->first_line, locp->last_line, locp->first_column, locp->last_column, txt);
46  }  }
47    
48  #define SCANNER_ERR(txt)  scanner_error(yylloc, yyextra, txt)  #define SCANNER_ERR(txt)  scanner_error(yylloc, yyextra, txt)
49  #define SCANNER_WRN(txt)  scanner_warning(yylloc, yyextra, txt)  #define SCANNER_WRN(txt)  scanner_warning(yylloc, yyextra, txt)
50    
51    // shut up warning that 'register' keyword is deprecated as of C++11
52    #if defined(__cplusplus) && __cplusplus >= 201103L
53    # define register
54    #endif
55    
56  using namespace LinuxSampler;  using namespace LinuxSampler;
57    
58    static int countNewLineChars(const char* txt) {
59        int n = 0;
60        for (int i = 0; txt[i]; ++i)
61            if (txt[i] == '\n') ++n;
62        return n;
63    }
64    
65    static int countCharsPastLastNewLine(const char* txt) {
66        const int n = (int)strlen(txt);
67        for (int i = n - 1; i >= 0; --i)
68            if (txt[i] == '\n')
69                return n - i - 1;
70        return n;
71    }
72    
73    #define processLocation() { \
74        const int nl = countNewLineChars(yytext); \
75        yylineno += nl; \
76        if (nl) yycolumn = countCharsPastLastNewLine(yytext); \
77    }
78    
79    // if compiled for debugging, throw an exception instead of exiting on fatal
80    // lexer errors (so the debugger may pause with the appropriate back trace)
81    #if DEBUG
82    # include <stdexcept>
83    # define YY_FATAL_ERROR(msg) throw std::runtime_error(msg)
84    #endif
85    
86  %}  %}
87    
88  /* use Flex's built-in support for line numbers */  /* use Flex's built-in support for line numbers
89  %option yylineno     (disabled, because it seems to be unreliable, so we are using our own
90       tracking code in the respective scanner rules below) */
91    /*%option yylineno*/
92  /* generate a reentrant safe scanner */  /* generate a reentrant safe scanner */
93  %option reentrant  %option reentrant
94  /* avoid symbol collision with other (i.e. future) scanner symbols */  /* avoid symbol collision with other (i.e. future) scanner symbols */
# Line 78  using namespace LinuxSampler; Line 108  using namespace LinuxSampler;
108  %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT  %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT
109    
110  DIGIT    [0-9]  DIGIT    [0-9]
111  ID       [a-zA-Z0-9_]*  ID       [a-zA-Z0-9_]+
112    
113  %%  %%
114    
# Line 89  ID       [a-zA-Z0-9_]* Line 119  ID       [a-zA-Z0-9_]*
119  }  }
120    
121  {DIGIT}+ {  {DIGIT}+ {
122      yylval->iValue = atoi(yytext);      if (sizeof(vmint) < 8)
123            yylval->iValue = atoi(yytext);
124        else
125            yylval->iValue = atoll(yytext);
126      return INTEGER;      return INTEGER;
127  }  }
128    
129  {DIGIT}+"."{DIGIT}* {   /* there is currently no support for floating point numbers in NKSP yet */
130     /*{DIGIT}+"."{DIGIT}* {
131      printf("A float: %s (%g)\n", yytext, atof(yytext));      printf("A float: %s (%g)\n", yytext, atof(yytext));
132  }   }*/
133    
134    
135   /* Preprocessor statement:  SET_CONDITION(name) */   /* Preprocessor statement:  SET_CONDITION(name) */
136    
137  <*>"SET_CONDITION"[ \t]*"(" {  <*>"SET_CONDITION"[ \t]*"(" {
138      printf("SET_CONDITION\n");      //printf("SET_CONDITION\n");
139      yy_push_state(PREPROC_SET_COND, yyscanner);      yy_push_state(PREPROC_SET_COND, yyscanner);
140  }  }
141  <PREPROC_SET_COND>{ID} {  <PREPROC_SET_COND>{ID} {
142      printf("preproc set condition '%s'\n", yytext);      //printf("preproc set condition '%s'\n", yytext);
143      bool success = yyextra->setPreprocessorCondition(yytext);      bool success = yyextra->setPreprocessorCondition(yytext);
144      if (!success) {      if (!success) {
145          SCANNER_WRN((String("Preprocessor: Condition '") +          SCANNER_WRN((String("Preprocessor: Condition '") +
# Line 113  ID       [a-zA-Z0-9_]* Line 147  ID       [a-zA-Z0-9_]*
147      }      }
148  }  }
149  <PREPROC_SET_COND>[ \t]*")" {  <PREPROC_SET_COND>[ \t]*")" {
150      printf("End of PREPROC_SET_COND\n");      //printf("End of PREPROC_SET_COND\n");
151      yy_pop_state(yyscanner);      yy_pop_state(yyscanner);
152  }  }
153    
# Line 121  ID       [a-zA-Z0-9_]* Line 155  ID       [a-zA-Z0-9_]*
155   /* Preprocessor statement:  RESET_CONDITION(name) */   /* Preprocessor statement:  RESET_CONDITION(name) */
156    
157  <*>"RESET_CONDITION"[ \t]*"(" {  <*>"RESET_CONDITION"[ \t]*"(" {
158      printf("RESET_CONDITION\n");      //printf("RESET_CONDITION\n");
159      yy_push_state(PREPROC_RESET_COND, yyscanner);      yy_push_state(PREPROC_RESET_COND, yyscanner);
160  }  }
161  <PREPROC_RESET_COND>{ID} {  <PREPROC_RESET_COND>{ID} {
162      printf("preproc reset condition '%s'\n", yytext);      //printf("preproc reset condition '%s'\n", yytext);
163      bool success = yyextra->resetPreprocessorCondition(yytext);      bool success = yyextra->resetPreprocessorCondition(yytext);
164      if (!success) {      if (!success) {
165          SCANNER_ERR((String("Preprocessor: could not reset condition '") +          SCANNER_ERR((String("Preprocessor: could not reset condition '") +
# Line 133  ID       [a-zA-Z0-9_]* Line 167  ID       [a-zA-Z0-9_]*
167      }      }
168  }  }
169  <PREPROC_RESET_COND>[ \t]*")" {  <PREPROC_RESET_COND>[ \t]*")" {
170      printf("End of RESET_CONDITION\n");      //printf("End of RESET_CONDITION\n");
171      yy_pop_state(yyscanner);      yy_pop_state(yyscanner);
172  }  }
173    
# Line 152  ID       [a-zA-Z0-9_]* Line 186  ID       [a-zA-Z0-9_]*
186   */   */
187    
188  <*>"USE_CODE_IF"[ \t]*"(" {  <*>"USE_CODE_IF"[ \t]*"(" {
189      printf("USE_CODE_IF\n");      //printf("{%s}\n", yytext);
190      yy_push_state(PREPROC_IF, yyscanner);      yy_push_state(PREPROC_IF, yyscanner);
191  }  }
192    <PREPROC_BODY_EAT>"USE_CODE_IF"[ \t]*"("{ID}")" {
193        //printf("[EAT{%s}\n", yytext);
194        yy_push_state(PREPROC_BODY_EAT, yyscanner);
195    }
196  <*>"USE_CODE_IF_NOT"[ \t]*"(" {  <*>"USE_CODE_IF_NOT"[ \t]*"(" {
197      printf("USE_CODE_IF_NOT\n");      //printf("USE_CODE_IF_NOT\n");
198      yy_push_state(PREPROC_IF_NOT, yyscanner);      yy_push_state(PREPROC_IF_NOT, yyscanner);
199  }  }
200    <PREPROC_BODY_EAT>"USE_CODE_IF_NOT"[ \t]*"("{ID}")" {
201        //printf("[EAT{%s}\n", yytext);
202        yy_push_state(PREPROC_BODY_EAT, yyscanner);
203    }
204  <PREPROC_IF>{ID} {  <PREPROC_IF>{ID} {
205      printf("preproc use code if '%s'\n", yytext);      //printf("preproc use code if '%s'\n", yytext);
206      yy_pop_state(yyscanner);      yy_pop_state(yyscanner);
207      if (yyextra->isPreprocessorConditionSet(yytext))      if (yyextra->isPreprocessorConditionSet(yytext))
208          yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);          yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
# Line 168  ID       [a-zA-Z0-9_]* Line 210  ID       [a-zA-Z0-9_]*
210          yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);          yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
211  }  }
212  <PREPROC_IF_NOT>{ID} {  <PREPROC_IF_NOT>{ID} {
213      printf("preproc use code if not '%s'\n", yytext);      //printf("preproc use code if not '%s'\n", yytext);
214      yy_pop_state(yyscanner);      yy_pop_state(yyscanner);
215      if (!yyextra->isPreprocessorConditionSet(yytext))      if (!yyextra->isPreprocessorConditionSet(yytext))
216          yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);          yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
# Line 180  ID       [a-zA-Z0-9_]* Line 222  ID       [a-zA-Z0-9_]*
222      yy_push_state(PREPROC_BODY_USE, yyscanner);      yy_push_state(PREPROC_BODY_USE, yyscanner);
223  }  }
224  <PREPROC_PRE_BODY_EAT>[ \t]*")" {  <PREPROC_PRE_BODY_EAT>[ \t]*")" {
225        //printf("PREPROCESSOR EAT : {%s}\n", yytext);
226      yy_pop_state(yyscanner);      yy_pop_state(yyscanner);
227      yy_push_state(PREPROC_BODY_EAT, yyscanner);      yy_push_state(PREPROC_BODY_EAT, yyscanner);
228  }  }
229  <*>.*"END_USE_CODE" {  <PREPROC_BODY_EAT,PREPROC_BODY_USE>"END_USE_CODE" {
230      printf("END_USE_CODE\n");      //printf("-->END_USE_CODE\n");
231      yy_pop_state(yyscanner);      yy_pop_state(yyscanner);
232  }  }
233    <PREPROC_BODY_EAT>[ \t\r\n]* { /* eat up code block filtered out by preprocessor */
234        //printf("PREPROCESSOR EAT2 : {%s}\n", yytext);
235        processLocation();
236    }
237    <PREPROC_BODY_EAT>.* { /* eat up code block filtered out by preprocessor */
238        //printf("PREPROCESSOR EAT3 : {%s}\n", yytext);
239        yyextra->addPreprocessorComment(yylloc->first_line, yylloc->last_line,
240                                        yylloc->first_column+1, yylloc->last_column+1);
241    }
242    
243    
244   /* Language keywords */   /* Language keywords */
# Line 198  ID       [a-zA-Z0-9_]* Line 250  ID       [a-zA-Z0-9_]*
250  "declare" return DECLARE;  "declare" return DECLARE;
251  "while" return WHILE;  "while" return WHILE;
252  "if" return IF;  "if" return IF;
253    ".or." return BITWISE_OR;
254  "or" return OR;  "or" return OR;
255  "release" return RELEASE;  "release" return RELEASE;
256    ".and." return BITWISE_AND;
257  "and" return AND;  "and" return AND;
258    ".not." return BITWISE_NOT;
259  "not" return NOT;  "not" return NOT;
260  "else" return ELSE;  "else" return ELSE;
261  "controller" return CONTROLLER;  "controller" return CONTROLLER;
# Line 209  ID       [a-zA-Z0-9_]* Line 264  ID       [a-zA-Z0-9_]*
264  "to" return TO;  "to" return TO;
265  "<=" return LE;  "<=" return LE;
266  ">=" return GE;  ">=" return GE;
267  "const" return CONST;  "const" return CONST_; // note: "CONST" is already defined for C/C++ compilers on Windows by default
268  "polyphonic" return POLYPHONIC;  "polyphonic" return POLYPHONIC;
269  "mod" return MOD;  "mod" return MOD;
270    "function" return FUNCTION;
271    "call" return CALL;
272    "synchronized" return SYNCHRONIZED;
273    
274  on|end|note|init|declare|if|then|begin|end|procedure|function {  [&,()[\]<>=*+#/-] {
275      printf("A keyword: %s\n", yytext);      return *yytext;
276  }  }
277    
278  [&,()[\]<>=*+#/-] { return *yytext; }  ("$"|"@"|"%"){ID} {
   
 ("$"|"@"){ID} {  
     yylval->sValue = strdup(yytext);  
     return VARIABLE;  
 }  
   
 "%"{ID} {  
279      yylval->sValue = strdup(yytext);      yylval->sValue = strdup(yytext);
280      return VARIABLE;      return VARIABLE;
281  }  }
# Line 237  on|end|note|init|declare|if|then|begin|e Line 288  on|end|note|init|declare|if|then|begin|e
288  ":=" return ASSIGNMENT;  ":=" return ASSIGNMENT;
289    
290  \n+ {  \n+ {
291         yylineno += countNewLineChars(yytext);
292         yycolumn = 0;
293      //printf("lex: new line %d\n", yylineno, yytext);      //printf("lex: new line %d\n", yylineno, yytext);
294      //return LF;      //return LF;
295  }  }
296    
297  "{"[^}]*"}" /* eat up comments */  "{"[^}]*"}" { /* eat up comments */
298        processLocation();
299    }
300    
301  [ \t\r]+ /* eat up whitespace */  [ \t\r]+ /* eat up whitespace */
302    
303  "..." /* eat up */  . {
304        printf( "Unrecognized character: '%s' (line %d, column %d)\n", yytext, yylineno, yycolumn);
305  . printf( "Unrecognized character: %s\n", yytext );      return UNKNOWN_CHAR;
306    }
307    
308  %%  %%
309    

Legend:
Removed from v.2581  
changed lines
  Added in v.3557

  ViewVC Help
Powered by ViewVC