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

Annotation of /linuxsampler/trunk/src/scriptvm/editor/nksp.l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3332 - (hide annotations) (download)
Mon Jul 24 18:51:21 2017 UTC (6 years, 8 months ago) by schoenebeck
File size: 8394 byte(s)
* NKSP script editor syntax highlighting API: catch all fatal lexer
  errors, to avoid the editor app to crash on ill-formed text input.
* Bumped version (2.0.0.svn74).

1 schoenebeck 2885 /*
2 schoenebeck 3260 * Copyright (c) 2015-2017 Christian Schoenebeck
3 schoenebeck 2885 *
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 used for generating syntax highlighting for NKSP instrument
11     script language code (this is not used by the sampler itself, but rather
12     provided for external script editor applications). */
13    
14     %{
15    
16     #include "NkspScanner.h"
17     // reentrant scanner data context
18     #define YY_EXTRA_TYPE NkspScanner*
19     // custom (f)lex input for reading from std::istream object
20     #define YY_INPUT(buf,result,max_size) \
21     { \
22     char c = yyextra->is->get(); \
23     if (yyextra->is->eof()) \
24     result = YY_NULL; \
25     else { \
26     buf[0] = c; \
27     result = 1; \
28     } \
29     }
30     // handle position (line, column) for each recognized token
31     #define YY_USER_ACTION \
32     yyextra->line = yylineno - 1; \
33     yyextra->column = yycolumn; \
34     yycolumn += yyleng;
35    
36     using namespace LinuxSampler;
37    
38     static int countNewLineChars(const char* txt) {
39     int n = 0;
40     for (int i = 0; txt[i]; ++i)
41     if (txt[i] == '\n') ++n;
42     return n;
43     }
44    
45 schoenebeck 3054 // shut up warning that 'register' keyword is deprecated as of C++11
46     #if defined(__cplusplus) && __cplusplus >= 201103L
47     # define register
48     #endif
49    
50 schoenebeck 3332 // Since this parser is solely used by script code editors, thus not used in a
51     // real-time context, always throw an exception instead of exiting on fatal
52 schoenebeck 3308 // lexer errors (so the debugger may pause with the appropriate back trace)
53 schoenebeck 3332 #include <stdexcept>
54     #define YY_FATAL_ERROR(msg) throw std::runtime_error(msg)
55 schoenebeck 3308
56 schoenebeck 2885 %}
57    
58     /* generate a reentrant safe scanner */
59     %option reentrant
60     /* avoid symbol collision with ones of other scanners */
61     %option prefix="Nksp_"
62     /* yywrap() would be called at EOF, we don't need it */
63     %option noyywrap
64     /* enable functions yy_push_state(), yy_pop_state(), yy_top_state() */
65     %option stack
66    
67     /* inclusive scanner conditions */
68     %s PREPROC_BODY_USE
69     /* exclusive scanner conditions */
70     %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT PREPROC_EVENT_NAME PREPROC_END_NAME
71    
72     DIGIT [0-9]
73 schoenebeck 2935 ID [a-zA-Z0-9_]+
74 schoenebeck 3308 END_ID on|while|if|select|function|synchronized
75 schoenebeck 2885
76     %%
77    
78     \"[^"]*\" {
79     yyextra->token = StringLiteralToken(yytext);
80     return yyextra->token.baseType;
81     }
82    
83     {DIGIT}+ {
84     yyextra->token = NumberLiteralToken(yytext);
85     return yyextra->token.baseType;
86     }
87    
88 schoenebeck 2935 /* there is currently no support for floating point numbers in NKSP yet */
89     /*{DIGIT}+"."{DIGIT}* {
90 schoenebeck 2885 yyextra->token = NumberLiteralToken(yytext);
91     return yyextra->token.baseType;
92 schoenebeck 2935 }*/
93 schoenebeck 2885
94    
95     /* Preprocessor statement: SET_CONDITION(name) */
96    
97     <*>"SET_CONDITION"[ \t]*"(" {
98     //printf("SET_CONDITION\n");
99     yy_push_state(PREPROC_SET_COND, yyscanner);
100     yyextra->token = PreprocessorToken(yytext);
101     return yyextra->token.baseType;
102     }
103     <PREPROC_SET_COND>{ID} {
104     //printf("preproc set condition '%s'\n", yytext);
105     yyextra->token = PreprocessorToken(yytext);
106     return yyextra->token.baseType;
107     }
108     <PREPROC_SET_COND>[ \t]*")" {
109     //printf("End of PREPROC_SET_COND\n");
110     yy_pop_state(yyscanner);
111     yyextra->token = PreprocessorToken(yytext);
112     return yyextra->token.baseType;
113     }
114    
115    
116     /* Preprocessor statement: RESET_CONDITION(name) */
117    
118     <*>"RESET_CONDITION"[ \t]*"(" {
119     //printf("RESET_CONDITION\n");
120     yy_push_state(PREPROC_RESET_COND, yyscanner);
121     yyextra->token = PreprocessorToken(yytext);
122     return yyextra->token.baseType;
123     }
124     <PREPROC_RESET_COND>{ID} {
125     //printf("preproc reset condition '%s'\n", yytext);
126     yyextra->token = PreprocessorToken(yytext);
127     return yyextra->token.baseType;
128     }
129     <PREPROC_RESET_COND>[ \t]*")" {
130     //printf("End of RESET_CONDITION\n");
131     yy_pop_state(yyscanner);
132     yyextra->token = PreprocessorToken(yytext);
133     return yyextra->token.baseType;
134     }
135    
136    
137     /* Preprocessor conditional statements:
138    
139     USE_CODE_IF(name)
140     ...
141     END_USE_CODE
142    
143     and:
144    
145     USE_CODE_IF_NOT(name)
146     ...
147     END_USE_CODE
148     */
149    
150     <*>"USE_CODE_IF"[ \t]*"(" {
151     //printf("USE_CODE_IF\n");
152     yy_push_state(PREPROC_IF, yyscanner);
153     yyextra->token = PreprocessorToken(yytext);
154     return yyextra->token.baseType;
155     }
156     <*>"USE_CODE_IF_NOT"[ \t]*"(" {
157     //printf("USE_CODE_IF_NOT\n");
158     yy_push_state(PREPROC_IF_NOT, yyscanner);
159     yyextra->token = PreprocessorToken(yytext);
160     return yyextra->token.baseType;
161     }
162     <PREPROC_IF>{ID} {
163     //printf("preproc use code if '%s'\n", yytext);
164     yy_pop_state(yyscanner);
165     yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
166     //yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
167     yyextra->token = PreprocessorToken(yytext);
168     return yyextra->token.baseType;
169     }
170     <PREPROC_IF_NOT>{ID} {
171     //printf("preproc use code if not '%s'\n", yytext);
172     yy_pop_state(yyscanner);
173     yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
174     //yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
175     yyextra->token = PreprocessorToken(yytext);
176     return yyextra->token.baseType;
177     }
178     <PREPROC_PRE_BODY_USE>[ \t]*")" {
179     yy_pop_state(yyscanner);
180     yy_push_state(PREPROC_BODY_USE, yyscanner);
181     yyextra->token = PreprocessorToken(yytext);
182     return yyextra->token.baseType;
183     }
184     <PREPROC_PRE_BODY_EAT>[ \t]*")" {
185     //printf("PREPROCESSOR EAT : \n");
186     yy_pop_state(yyscanner);
187     yy_push_state(PREPROC_BODY_EAT, yyscanner);
188     yyextra->token = PreprocessorToken(yytext);
189     return yyextra->token.baseType;
190     }
191     <*>.*"END_USE_CODE" {
192     //printf("-->END_USE_CODE\n");
193     yy_pop_state(yyscanner);
194     yyextra->token = PreprocessorToken(yytext);
195     return yyextra->token.baseType;
196     }
197     <PREPROC_BODY_EAT>[ \t\r\n]* /* eat up code block filtered out by preprocessor */
198     <PREPROC_BODY_EAT>.* /* eat up code block filtered out by preprocessor */
199    
200    
201     /* Event Handler Names (only if they occur alone in a document!) */
202    
203     ^\s*(init|note|release|controller) {
204     yyextra->token = EventHandlerNameToken(yytext);
205     return yyextra->token.baseType;
206     }
207    
208    
209     /* Language keywords */
210    
211     on {
212     yy_push_state(PREPROC_EVENT_NAME, yyscanner);
213     yyextra->token = KeywordToken(yytext);
214     return yyextra->token.baseType;
215     }
216    
217     <PREPROC_EVENT_NAME>[ \t]*{ID} {
218     yy_pop_state(yyscanner);
219     yyextra->token = EventHandlerNameToken(yytext);
220     return yyextra->token.baseType;
221     }
222    
223     end {
224     yy_push_state(PREPROC_END_NAME, yyscanner);
225     yyextra->token = KeywordToken(yytext);
226     return yyextra->token.baseType;
227     }
228    
229 schoenebeck 3308 <PREPROC_END_NAME>[ \t]*{END_ID}? {
230 schoenebeck 2885 yy_pop_state(yyscanner);
231     yyextra->token = KeywordToken(yytext);
232     return yyextra->token.baseType;
233     }
234    
235 schoenebeck 2935 ".or."|".and."|".not." {
236     yyextra->token = KeywordToken(yytext);
237     return yyextra->token.baseType;
238     }
239    
240 schoenebeck 3260 declare|while|if|or|and|not|else|case|select|to|mod|const|polyphonic|function|call|synchronized {
241 schoenebeck 2885 yyextra->token = KeywordToken(yytext);
242     return yyextra->token.baseType;
243     }
244    
245    
246     /* Variables */
247    
248     "$"{ID} {
249     yyextra->token = IntegerVariableToken(yytext);
250     return yyextra->token.baseType;
251     }
252    
253     "@"{ID} {
254     yyextra->token = StringVariableToken(yytext);
255     return yyextra->token.baseType;
256     }
257    
258     "%"{ID} {
259     yyextra->token = ArrayVariableToken(yytext);
260     return yyextra->token.baseType;
261     }
262    
263     {ID} {
264     yyextra->token = IdentifierToken(yytext);
265     return yyextra->token.baseType;
266     }
267    
268    
269     /* other */
270    
271     <*>\n {
272     yyextra->token = NewLineToken();
273     ++yylineno;
274     yycolumn = 0;
275     return yyextra->token.baseType;
276     }
277    
278     "{"[^}]*"}" {
279     yyextra->token = CommentToken(yytext);
280     yylineno += countNewLineChars(yytext);
281     return yyextra->token.baseType;
282     }
283    
284     <*>\t {
285     yyextra->token = OtherToken(" ");
286     return yyextra->token.baseType;
287     }
288    
289     \r+ /* eat up \r */
290    
291     <<EOF>> {
292     yyextra->token = EofToken();
293     yyterminate();
294     }
295    
296     <*>. {
297     yyextra->token = OtherToken(yytext);
298     return yyextra->token.baseType;
299     }
300    
301    
302     %%
303    
304     namespace LinuxSampler {
305    
306     int NkspScanner::processScanner() {
307     return Nksp_lex(scanner);
308     }
309    
310     void NkspScanner::createScanner(std::istream* is) {
311     if (scanner) destroyScanner();
312     this->is = is;
313     Nksp_lex_init(&scanner);
314     Nksp_set_extra(this, scanner);
315     }
316    
317     void NkspScanner::destroyScanner() {
318     if (!scanner) return;
319     Nksp_lex_destroy(scanner);
320     scanner = NULL;
321     }
322    
323     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC