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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2889 - (hide annotations) (download)
Mon Apr 25 17:28:23 2016 UTC (8 years ago) by schoenebeck
File size: 7804 byte(s)
* Added new C++ API class "ScriptVMFactory".
* Instrument Scripts: extended parser issues to provide not only first
  line and first column, but also last line and last column of issue
  (thus marking the precise span of the issue within the source code).
* Bumped version (2.0.0.svn7).

1 schoenebeck 2581 /*
2 schoenebeck 2888 * Copyright (c) 2014-2016 Christian Schoenebeck and Andreas Persson
3 schoenebeck 2581 *
4     * http://www.linuxsampler.org
5     *
6     * This file is part of LinuxSampler and released under the same terms.
7     * See README file for details.
8     */
9    
10 schoenebeck 2888 /* Token scanner for NKSP real-time instrument script language. */
11 schoenebeck 2581
12     %{
13    
14     #include "parser_shared.h"
15     #include <math.h>
16     // reentrant scanner data context
17     #define YY_EXTRA_TYPE ParserContext*
18     // set line number each time a token is recognized
19     #define YY_USER_ACTION \
20     { \
21     yylloc->first_line = yylineno; \
22     yylloc->last_line = yylineno; \
23 schoenebeck 2888 yylloc->first_column = yycolumn; \
24     yycolumn += yyleng; \
25     yylloc->last_column = yycolumn - 1; \
26 schoenebeck 2581 /*printf("lex: line '%s'\n", yytext);*/ \
27     }
28     // custom (f)lex input for reading from std::istream object
29     #define YY_INPUT(buf,result,max_size) \
30     { \
31     char c = yyextra->is->get(); \
32     if (yyextra->is->eof()) \
33     result = YY_NULL; \
34     else { \
35     buf[0] = c; \
36     result = 1; \
37     } \
38     }
39    
40     static void scanner_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {
41 schoenebeck 2889 context->addErr(locp->first_line, locp->last_line, locp->first_column, locp->last_column, err);
42 schoenebeck 2581 }
43    
44     static void scanner_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {
45 schoenebeck 2889 context->addWrn(locp->first_line, locp->last_line, locp->first_column, locp->last_column, txt);
46 schoenebeck 2581 }
47    
48     #define SCANNER_ERR(txt) scanner_error(yylloc, yyextra, txt)
49     #define SCANNER_WRN(txt) scanner_warning(yylloc, yyextra, txt)
50    
51     using namespace LinuxSampler;
52    
53 schoenebeck 2888 static int countNewLineChars(const char* txt) {
54     int n = 0;
55     for (int i = 0; txt[i]; ++i)
56     if (txt[i] == '\n') ++n;
57     return n;
58     }
59    
60     static int countCharsPastLastNewLine(const char* txt) {
61     const int n = strlen(txt);
62     for (int i = n - 1; i >= 0; --i)
63     if (txt[i] == '\n')
64     return n - i - 1;
65     return n;
66     }
67    
68     #define processLocation() { \
69     const int nl = countNewLineChars(yytext); \
70     yylineno += nl; \
71     if (nl) yycolumn = countCharsPastLastNewLine(yytext); \
72     }
73    
74 schoenebeck 2581 %}
75    
76 schoenebeck 2888 /* use Flex's built-in support for line numbers
77     (disabled, because it seems to be unreliable, so we are using our own
78     tracking code in the respective scanner rules below) */
79     /*%option yylineno*/
80 schoenebeck 2581 /* generate a reentrant safe scanner */
81     %option reentrant
82     /* avoid symbol collision with other (i.e. future) scanner symbols */
83     %option prefix="InstrScript_"
84     /* bison-bridge adds an argument yylval to yylex, and bison-locations adds an
85     argument code yylloc for location tracking. */
86     %option bison-bridge
87     %option bison-locations
88     /* yywrap() would be called at EOF, we don't need it */
89     %option noyywrap
90     /* enable functions yy_push_state(), yy_pop_state(), yy_top_state() */
91     %option stack
92    
93     /* inclusive scanner conditions */
94     %s PREPROC_BODY_USE
95     /* exclusive scanner conditions */
96     %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT
97    
98     DIGIT [0-9]
99     ID [a-zA-Z0-9_]*
100    
101     %%
102    
103     \"[^"]*\" {
104     yylval->sValue = strdup(yytext + 1);
105     yylval->sValue[strlen(yylval->sValue) - 1] = '\0';
106     return STRING;
107     }
108    
109     {DIGIT}+ {
110     yylval->iValue = atoi(yytext);
111     return INTEGER;
112     }
113    
114     {DIGIT}+"."{DIGIT}* {
115     printf("A float: %s (%g)\n", yytext, atof(yytext));
116     }
117    
118    
119     /* Preprocessor statement: SET_CONDITION(name) */
120    
121     <*>"SET_CONDITION"[ \t]*"(" {
122 schoenebeck 2588 //printf("SET_CONDITION\n");
123 schoenebeck 2581 yy_push_state(PREPROC_SET_COND, yyscanner);
124     }
125     <PREPROC_SET_COND>{ID} {
126 schoenebeck 2588 //printf("preproc set condition '%s'\n", yytext);
127 schoenebeck 2581 bool success = yyextra->setPreprocessorCondition(yytext);
128     if (!success) {
129     SCANNER_WRN((String("Preprocessor: Condition '") +
130     yytext + "' is already set.").c_str());
131     }
132     }
133     <PREPROC_SET_COND>[ \t]*")" {
134 schoenebeck 2588 //printf("End of PREPROC_SET_COND\n");
135 schoenebeck 2581 yy_pop_state(yyscanner);
136     }
137    
138    
139     /* Preprocessor statement: RESET_CONDITION(name) */
140    
141     <*>"RESET_CONDITION"[ \t]*"(" {
142 schoenebeck 2588 //printf("RESET_CONDITION\n");
143 schoenebeck 2581 yy_push_state(PREPROC_RESET_COND, yyscanner);
144     }
145     <PREPROC_RESET_COND>{ID} {
146 schoenebeck 2588 //printf("preproc reset condition '%s'\n", yytext);
147 schoenebeck 2581 bool success = yyextra->resetPreprocessorCondition(yytext);
148     if (!success) {
149     SCANNER_ERR((String("Preprocessor: could not reset condition '") +
150     yytext + "' (either not set or a built-in condition).").c_str());
151     }
152     }
153     <PREPROC_RESET_COND>[ \t]*")" {
154 schoenebeck 2588 //printf("End of RESET_CONDITION\n");
155 schoenebeck 2581 yy_pop_state(yyscanner);
156     }
157    
158    
159     /* Preprocessor conditional statements:
160    
161     USE_CODE_IF(name)
162     ...
163     END_USE_CODE
164    
165     and:
166    
167     USE_CODE_IF_NOT(name)
168     ...
169     END_USE_CODE
170     */
171    
172     <*>"USE_CODE_IF"[ \t]*"(" {
173 schoenebeck 2588 //printf("USE_CODE_IF\n");
174 schoenebeck 2581 yy_push_state(PREPROC_IF, yyscanner);
175     }
176     <*>"USE_CODE_IF_NOT"[ \t]*"(" {
177 schoenebeck 2588 //printf("USE_CODE_IF_NOT\n");
178 schoenebeck 2581 yy_push_state(PREPROC_IF_NOT, yyscanner);
179     }
180     <PREPROC_IF>{ID} {
181 schoenebeck 2588 //printf("preproc use code if '%s'\n", yytext);
182 schoenebeck 2581 yy_pop_state(yyscanner);
183     if (yyextra->isPreprocessorConditionSet(yytext))
184     yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
185     else
186     yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
187     }
188     <PREPROC_IF_NOT>{ID} {
189 schoenebeck 2588 //printf("preproc use code if not '%s'\n", yytext);
190 schoenebeck 2581 yy_pop_state(yyscanner);
191     if (!yyextra->isPreprocessorConditionSet(yytext))
192     yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
193     else
194     yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
195     }
196     <PREPROC_PRE_BODY_USE>[ \t]*")" {
197     yy_pop_state(yyscanner);
198     yy_push_state(PREPROC_BODY_USE, yyscanner);
199     }
200     <PREPROC_PRE_BODY_EAT>[ \t]*")" {
201 schoenebeck 2588 //printf("PREPROCESSOR EAT : \n");
202 schoenebeck 2581 yy_pop_state(yyscanner);
203     yy_push_state(PREPROC_BODY_EAT, yyscanner);
204     }
205     <*>.*"END_USE_CODE" {
206 schoenebeck 2588 //printf("-->END_USE_CODE\n");
207 schoenebeck 2581 yy_pop_state(yyscanner);
208     }
209 schoenebeck 2888 <PREPROC_BODY_EAT>[ \t\r\n]* { /* eat up code block filtered out by preprocessor */
210     processLocation();
211     }
212     <PREPROC_BODY_EAT>.* { /* eat up code block filtered out by preprocessor */
213     processLocation();
214     }
215 schoenebeck 2581
216    
217     /* Language keywords */
218    
219     "on" return ON;
220     "end" return END;
221     "note" return NOTE;
222     "init" return INIT;
223     "declare" return DECLARE;
224     "while" return WHILE;
225     "if" return IF;
226     "or" return OR;
227     "release" return RELEASE;
228     "and" return AND;
229     "not" return NOT;
230     "else" return ELSE;
231     "controller" return CONTROLLER;
232     "case" return CASE;
233     "select" return SELECT;
234     "to" return TO;
235     "<=" return LE;
236     ">=" return GE;
237 schoenebeck 2585 "const" return CONST_; // note: "CONST" is already defined for C/C++ compilers on Windows by default
238 schoenebeck 2581 "polyphonic" return POLYPHONIC;
239     "mod" return MOD;
240    
241     on|end|note|init|declare|if|then|begin|end|procedure|function {
242     printf("A keyword: %s\n", yytext);
243     }
244    
245     [&,()[\]<>=*+#/-] { return *yytext; }
246    
247     ("$"|"@"){ID} {
248     yylval->sValue = strdup(yytext);
249     return VARIABLE;
250     }
251    
252     "%"{ID} {
253     yylval->sValue = strdup(yytext);
254     return VARIABLE;
255     }
256    
257     {ID} {
258     yylval->sValue = strdup(yytext);
259     return IDENTIFIER;
260     }
261    
262     ":=" return ASSIGNMENT;
263    
264     \n+ {
265 schoenebeck 2888 yylineno += countNewLineChars(yytext);
266     yycolumn = 0;
267 schoenebeck 2581 //printf("lex: new line %d\n", yylineno, yytext);
268     //return LF;
269     }
270    
271 schoenebeck 2888 "{"[^}]*"}" { /* eat up comments */
272     processLocation();
273     }
274 schoenebeck 2581
275     [ \t\r]+ /* eat up whitespace */
276    
277     "..." /* eat up */
278    
279     . printf( "Unrecognized character: %s\n", yytext );
280    
281     %%
282    
283     namespace LinuxSampler {
284    
285     void ParserContext::createScanner(std::istream* is) {
286     if (scanner) destroyScanner();
287     this->is = is;
288     yylex_init(&scanner);
289     yyset_extra(this, scanner);
290     }
291    
292     void ParserContext::destroyScanner() {
293     if (!scanner) return;
294     yylex_destroy(scanner);
295     scanner = NULL;
296     }
297    
298     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC