4 Ann Hell Ex Machina - Music Software
5 Copyright (C) 2003/2006 Angel Ortega <angel@triptico.com>
7 compiler.l - Scripting language [F]lex lexer
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 http://www.triptico.com
35 void yyerror(char * s);
36 int yy_input_for_flex(char * buf, int max);
39 static char * ascii_notes = "ccddeffggaab";
41 /* redefinition of input function for GNU Flex */
43 #define YY_INPUT(b,r,m) (r = yy_input_for_flex(b,m))
47 char * code; /* code string */
48 int offset; /* current offset */
51 static struct code_stack * code_stack = NULL;
52 static int code_stack_i = -1;
54 /* dynamic string manipulation macros */
56 struct ds { char * d; int p; int s; };
57 #define ds_init(x) do { x.d = (char *)0; x.p = x.s = 0; } while(0)
58 #define ds_rewind(x) x.p = 0;
59 #define ds_free(x) do { if(x.d) free(x.d); ds_init(x); } while(0)
60 #define ds_redim(x) do { if(x.p >= x.s) x.d = realloc(x.d, x.s += 32); } while(0)
61 #define ds_poke(x,c) do { ds_redim(x); x.d[x.p++] = c; } while(0)
62 #define ds_pokes(x,t) do { char *p = t; while(*p) ds_poke(x, *p++); } while(0)
66 static struct ds ds_blk;
68 /* count of parentheses */
78 S_INTEGER [-+]{P_INTEGER}
79 P_REAL {DIGIT}*[\.]?{DIGIT}+
86 MARKNAME [-a-zA-Z0-9_]+
89 ASSERT_MARK !{MARKNAME}
91 BLOCKNAME [-a-zA-Z0-9_]+
100 /* integers without sign */
101 yylval.i = atoi(yytext);
105 /* signed integers */
106 yylval.i = atoi(yytext);
110 /* real numbers without sign */
111 yylval.d = atof(yytext);
115 /* signel real numbers */
116 yylval.d = atof(yytext);
122 yylval.i = strchr(ascii_notes, *yytext) - ascii_notes;
125 {NOTE_T3} { return(NOTE_T3); }
126 {NOTE_T5} { return(NOTE_T5); }
129 /* create new mark */
130 yylval.p = yytext + 1;
135 yylval.p = yytext + 1;
140 yylval.p = yytext + 1;
144 {WSPACE} { ; /* ignore blanks */ }
148 \/\* { BEGIN REM; /* C-like comments */ }
149 <REM>\*\/ { BEGIN 0; }
150 <REM>\n { yyline++; }
151 <REM>. { ; /* drop anything inside a comment */ }
153 \{ { BEGIN XC; /* start of extended commands */ }
155 /* double-quoted string */
156 yytext[yyleng - 1] = '\0';
157 yylval.p = strdup(yytext + 1);
161 /* single-quoted string */
162 yytext[yyleng - 1] = '\0';
163 yylval.p = strdup(yytext + 1);
167 yylval.i = atoi(yytext);
171 yylval.i = atoi(yytext);
175 yylval.d = atof(yytext);
179 yylval.d = atof(yytext);
183 /* frame count, in seconds */
184 yytext[yyleng - 1] = '\0';
185 yylval.d = atof(yytext) * 1000;
189 /* frame count, in milliseconds */
190 yytext[yyleng - 2] = '\0';
191 yylval.d = atof(yytext);
194 <XC>{NOTE_P}[\#\&]?{P_INTEGER} {
198 yylval.i = strchr(ascii_notes, *ptr) - ascii_notes;
201 /* process optional sharps or flats */
215 yylval.i += atoi(ptr) * 12;
220 <XC>wav { return(SS_WAV); }
221 <XC>pat { return(SS_PAT); }
222 <XC>sustain { return(SS_SUSTAIN); }
223 <XC>vibrato { return(SS_VIBRATO); }
224 <XC>channel { return(SS_CHANNEL); }
225 <XC>vol { return(SS_VOL); }
227 <XC>delay { return(SS_EFF_DELAY); }
228 <XC>echo { return(SS_EFF_ECHO); }
229 <XC>comb { return(SS_EFF_COMB); }
230 <XC>allpass { return(SS_EFF_ALLPASS); }
231 <XC>flanger { return(SS_EFF_FLANGER); }
232 <XC>wobble { return(SS_EFF_WOBBLE); }
233 <XC>square_wobble { return(SS_EFF_SQWOBBLE); }
234 <XC>fader { return(SS_EFF_FADER); }
235 <XC>reverb { return(SS_EFF_REVERB); }
236 <XC>off { return(SS_EFF_OFF); }
238 <XC>pitch_stretch { return(SS_PITCH_STRETCH); }
239 <XC>time_stretch { return(SS_TIME_STRETCH); }
240 <XC>print_wave_tempo { return(SS_PRINT_WAVE_TEMPO); }
242 <XC>song_info { return(SONG_INFO); }
244 <XC>midi_channel { return(MIDI_CHANNEL); }
245 <XC>midi_program { return(MIDI_PROGRAM); }
246 <XC>midi_generic { return(MIDI_GENERIC); }
248 <XC>\/\* { BEGIN REMXC; /* C-like comments inside XC */ }
249 <REMXC>\*\/ { BEGIN XC; /* jump back to XC processing */ }
250 <REMXC>\n { yyline++; }
254 <XC>{WSPACE} { ; /* ignore blanks */ }
256 <XC>. { return(*yytext); }
264 <BLK>\( { ds_blk_i++; ds_poke(ds_blk, *yytext); }
266 /* one parentheses less */
272 ds_poke(ds_blk, '\0');
279 ds_poke(ds_blk, ')');
281 <BLK>\n { ds_poke(ds_blk, ' '); yyline++; }
282 <BLK>. { ds_poke(ds_blk, *yytext); }
284 =[ \t\n]*{BLOCKNAME} {
285 /* block assignation */
286 yylval.p = yytext + 1;
288 /* skip (possible) spaces between
289 the = and the blockname; this lex
290 rule is written this way to avoid
291 having a global match for {BLOCKNAME},
292 that could swallow notes and such,
293 being mismatched as blocknames */
294 while(*yylval.p == ' ' ||
302 /* block insertion */
303 yylval.p = yytext + 1;
308 yytext[yyleng - 1] = '\0';
309 yylval.p = yytext + 1;
313 . { return(*yytext); }
317 int yywrap(void) { return(1); }
319 char * ds_load(char * file)
325 if((f = libpath_fopen(file, "r")) == NULL)
330 while((c = fgetc(f)) != EOF)
340 int push_code(char * code)
342 struct code_stack * cs;
345 GROW(code_stack, code_stack_i, struct code_stack);
347 cs = &code_stack[code_stack_i];
356 int push_code_from_file(char * file)
360 if((c = ds_load(file)) == NULL)
368 int code_getchar(void)
370 struct code_stack * cs;
373 while(c == '\0' && code_stack_i > -1)
375 /* get current char */
376 cs = &code_stack[code_stack_i];
377 c = cs->code[cs->offset++];
385 /* move to previous */
388 /* in any case, return a separator */
397 int yy_input_for_flex(char * buf, int max)
399 buf[0] = code_getchar();
401 return(buf[0] == '\0' ? 0 : 1);