/[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 2581 - (show annotations) (download)
Fri May 30 12:48:05 2014 UTC (5 years ago) by schoenebeck
File size: 6910 byte(s)
* (WIP) Implemented parser and VM for upcoming new real-time instrument
  script support. It needs yet to be integrated into the sampler's
  sampler engines. You can toy around for now with the command line tool
  "ls_instr_script" and i.e. examples showing the core language features
  under src/scriptvm/examples/.
* Bumped version (1.0.0.svn41).

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

  ViewVC Help
Powered by ViewVC