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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2889 - (show 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 /*
2 * Copyright (c) 2014-2016 Christian Schoenebeck and Andreas Persson
3 *
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 /* Token scanner for NKSP real-time instrument script language. */
11
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 yylloc->first_column = yycolumn; \
24 yycolumn += yyleng; \
25 yylloc->last_column = yycolumn - 1; \
26 /*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 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) {
45 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)
49 #define SCANNER_WRN(txt) scanner_warning(yylloc, yyextra, txt)
50
51 using namespace LinuxSampler;
52
53 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 %}
75
76 /* 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 /* 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 //printf("SET_CONDITION\n");
123 yy_push_state(PREPROC_SET_COND, yyscanner);
124 }
125 <PREPROC_SET_COND>{ID} {
126 //printf("preproc set condition '%s'\n", yytext);
127 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 //printf("End of PREPROC_SET_COND\n");
135 yy_pop_state(yyscanner);
136 }
137
138
139 /* Preprocessor statement: RESET_CONDITION(name) */
140
141 <*>"RESET_CONDITION"[ \t]*"(" {
142 //printf("RESET_CONDITION\n");
143 yy_push_state(PREPROC_RESET_COND, yyscanner);
144 }
145 <PREPROC_RESET_COND>{ID} {
146 //printf("preproc reset condition '%s'\n", yytext);
147 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 //printf("End of RESET_CONDITION\n");
155 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 //printf("USE_CODE_IF\n");
174 yy_push_state(PREPROC_IF, yyscanner);
175 }
176 <*>"USE_CODE_IF_NOT"[ \t]*"(" {
177 //printf("USE_CODE_IF_NOT\n");
178 yy_push_state(PREPROC_IF_NOT, yyscanner);
179 }
180 <PREPROC_IF>{ID} {
181 //printf("preproc use code if '%s'\n", yytext);
182 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 //printf("preproc use code if not '%s'\n", yytext);
190 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 //printf("PREPROCESSOR EAT : \n");
202 yy_pop_state(yyscanner);
203 yy_push_state(PREPROC_BODY_EAT, yyscanner);
204 }
205 <*>.*"END_USE_CODE" {
206 //printf("-->END_USE_CODE\n");
207 yy_pop_state(yyscanner);
208 }
209 <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
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 "const" return CONST_; // note: "CONST" is already defined for C/C++ compilers on Windows by default
238 "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 yylineno += countNewLineChars(yytext);
266 yycolumn = 0;
267 //printf("lex: new line %d\n", yylineno, yytext);
268 //return LF;
269 }
270
271 "{"[^}]*"}" { /* eat up comments */
272 processLocation();
273 }
274
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