Cue commands are indented.
[ahxm.git] / compiler.l
blobde53b1431cbefc8f92e776a74376ddf447a0863a
1 %{
2 /*
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
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include "y.tab.h"
33 #include "annhell.h"
35 void yyerror(char * s);
36 int yy_input_for_flex(char * buf, int max);
38 /* the notes */
39 static char * ascii_notes="ccddeffggaab";
41 /* redefinition of input function for GNU Flex */
42 #undef YY_INPUT
43 #define YY_INPUT(b,r,m) (r=yy_input_for_flex(b,m))
45 #define MAX_INPUTS 256
47 struct code_stack
49         char * code;    /* code string */
50         int offset;     /* current offset */
51         int times;      /* times to be fed to lexer/parser */
52         int dyn;        /* if set, free() after usage */
55 static struct code_stack code_stack[MAX_INPUTS];
56 static int code_stack_i=-1;
58 /* dynamic string manipulation macros */
59 #ifndef ds_init
60 struct ds { char * d; int p; int s; };
61 #define ds_init(x) do { x.d=(char *)0; x.p=x.s=0; } while(0)
62 #define ds_rewind(x) x.p=0;
63 #define ds_free(x) do { if(x.d) free(x.d); ds_init(x); } while(0)
64 #define ds_redim(x) do { if(x.p >= x.s) x.d=realloc(x.d, x.s += 32); } while(0)
65 #define ds_poke(x,c) do { ds_redim(x); x.d[x.p++]=c; } while(0)
66 #define ds_pokes(x,t) do { char *p=t; while(*p) ds_poke(x, *p++); } while(0)
67 #endif /* ds_init */
69 /* block dynstring */
70 static struct ds ds_blk;
72 /* count of parentheses */
73 static int ds_blk_i;
75 /* line number */
76 int yyline=0;
80 DIGIT           [0-9]
81 P_INTEGER       {DIGIT}+
82 S_INTEGER       [-+]{P_INTEGER}
83 P_REAL          {DIGIT}*[\.]?{DIGIT}+
84 S_REAL          [-+]{P_REAL}
86 NOTE_P          [a-g]
87 NOTE_T3         \/3
88 NOTE_T5         \/5
90 MARKNAME        [-a-zA-Z0-9_]+
91 NEW_MARK        \^{MARKNAME}
92 GOTO_MARK       @{MARKNAME}
93 ASSERT_MARK     !{MARKNAME}
95 BLOCKNAME       [-a-zA-Z0-9_]+
97 WSPACE          [ \t]+
99 %x REM XC REMXC BLK
103 {P_INTEGER}             {
104                                 /* integers without sign */
105                                 yylval.i=atoi(yytext);
106                                 return(P_INTEGER);
107                         }
108 {S_INTEGER}             {
109                                 /* signed integers */
110                                 yylval.i=atoi(yytext);
111                                 return(S_INTEGER);
112                         }
113 {P_REAL}                {
114                                 /* real numbers without sign */
115                                 yylval.d=atof(yytext);
116                                 return(P_REAL);
117                         }
118 {S_REAL}                {
119                                 /* signel real numbers */
120                                 yylval.d=atof(yytext);
121                                 return(S_REAL);
122                         }
124 {NOTE_P}                {
125                                 /* note pitch */
126                                 yylval.i=strchr(ascii_notes, *yytext) - ascii_notes;
127                                 return(NOTE_P);
128                         }
129 {NOTE_T3}               { return(NOTE_T3); }
130 {NOTE_T5}               { return(NOTE_T5); }
132 {NEW_MARK}              {
133                                 /* create new mark */
134                                 yylval.p=yytext + 1;
135                                 return(NEW_MARK);
136                         }
137 {GOTO_MARK}             {
138                                 /* go to mark */
139                                 yylval.p=yytext + 1;
140                                 return(GOTO_MARK);
141                         }
142 {ASSERT_MARK}           {
143                                 /* assert mark */
144                                 yylval.p=yytext + 1;
145                                 return(ASSERT_MARK);
146                         }
148 {WSPACE}                { ; /* ignore blanks */ }
150 \n                      { yyline++; }
152 \/\*                    { BEGIN REM; /* C-like comments */ }
153 <REM>\*\/               { BEGIN 0; }
154 <REM>\n                 { yyline++; }
155 <REM>.                  { ; /* drop anything inside a comment */ }
157 \{                      { BEGIN XC; /* start of extended commands */ }
158 <XC>\"[^\"]*\"          {
159                                 /* double-quoted string */
160                                 yytext[yyleng - 1]='\0';
161                                 yylval.p=strdup(yytext + 1);
162                                 return(XC_STR);
163                         }
164 <XC>\'[^\']*\'          {
165                                 /* single-quoted string */
166                                 yytext[yyleng - 1]='\0';
167                                 yylval.p=strdup(yytext + 1);
168                                 return(XC_STR);
169                         }
170 <XC>{P_INTEGER}         {
171                                 yylval.i=atoi(yytext);
172                                 return(P_INTEGER);
173                         }
174 <XC>{S_INTEGER}         {
175                                 yylval.i=atoi(yytext);
176                                 return(S_INTEGER);
177                         }
178 <XC>{P_REAL}            {
179                                 yylval.d=atof(yytext);
180                                 return(P_REAL);
181                         }
182 <XC>{S_REAL}            {
183                                 yylval.d=atof(yytext);
184                                 return(S_REAL);
185                         }
186 <XC>{P_REAL}s           {
187                                 /* frame count, in seconds */
188                                 yytext[yyleng - 1]='\0';
189                                 yylval.d=atof(yytext) * 1000;
190                                 return(XC_MSECS);
191                         }
192 <XC>{P_REAL}ms          {
193                                 /* frame count, in milliseconds */
194                                 yytext[yyleng - 2]='\0';
195                                 yylval.d=atof(yytext);
196                                 return(XC_MSECS);
197                         }
198 <XC>{NOTE_P}[\#\&]?{P_INTEGER} {
199                                 char * ptr=yytext;
201                                 /* process note */
202                                 yylval.i=strchr(ascii_notes, *ptr) - ascii_notes;
203                                 ptr++;
205                                 /* process optional sharps or flats */
206                                 if(*ptr == '#')
207                                 {
208                                         yylval.i++;
209                                         ptr++;
210                                 }
211                                 else
212                                 if(*ptr == '&')
213                                 {
214                                         yylval.i--;
215                                         ptr++;
216                                 }
218                                 /* process octave */
219                                 yylval.i += atoi(ptr) * 12;
221                                 return(XC_ABSNOTE);
222                         }
224 <XC>wav                 { return(SS_WAV); }
225 <XC>pat                 { return(SS_PAT); }
226 <XC>sustain             { return(SS_SUSTAIN); }
227 <XC>vibrato             { return(SS_VIBRATO); }
228 <XC>channel             { return(SS_CHANNEL); }
229 <XC>vol                 { return(SS_VOL); }
231 <XC>delay               { return(SS_EFF_DELAY); }
232 <XC>echo                { return(SS_EFF_ECHO); }
233 <XC>comb                { return(SS_EFF_COMB); }
234 <XC>allpass             { return(SS_EFF_ALLPASS); }
235 <XC>flanger             { return(SS_EFF_FLANGER); }
236 <XC>wobble              { return(SS_EFF_WOBBLE); }
237 <XC>square_wobble       { return(SS_EFF_SQWOBBLE); }
238 <XC>fader               { return(SS_EFF_FADER); }
239 <XC>reverb              { return(SS_EFF_REVERB); }
240 <XC>off                 { return(SS_EFF_OFF); }
242 <XC>pitch_stretch       { return(SS_PITCH_STRETCH); }
243 <XC>time_stretch        { return(SS_TIME_STRETCH); }
244 <XC>print_wave_tempo    { return(SS_PRINT_WAVE_TEMPO); }
246 <XC>track               { return(TRACK_INFO); }
248 <XC>midi_channel        { return(MIDI_CHANNEL); }
249 <XC>midi_program        { return(MIDI_PROGRAM); }
250 <XC>midi_generic        { return(MIDI_GENERIC); }
252 <XC>\/\*                { BEGIN REMXC; /* C-like comments inside XC */ }
253 <REMXC>\*\/             { BEGIN XC; /* jump back to XC processing */ }
254 <REMXC>\n               { yyline++; }
255 <REMXC>.                { ; }
257 <XC>\}                  { BEGIN 0; }
258 <XC>{WSPACE}            { ; /* ignore blanks */ }
259 <XC>\n                  { yyline++; }
260 <XC>.                   { return(*yytext); }
262 \(                      {
263                                 /* start of block */
264                                 ds_init(ds_blk);
265                                 ds_blk_i=1;
266                                 BEGIN BLK;
267                         }
268 <BLK>\(                 { ds_blk_i++; ds_poke(ds_blk, *yytext); }
269 <BLK>\)                 {
270                                 /* one parentheses less */
271                                 ds_blk_i--;
273                                 /* ok with block? */
274                                 if(ds_blk_i == 0)
275                                 {
276                                         ds_poke(ds_blk, '\0');
277                                         yylval.p=ds_blk.d;
279                                         BEGIN 0;
280                                         return(BLOCK);
281                                 }
282                                 else
283                                         ds_poke(ds_blk, ')');
284                         }
285 <BLK>\n                 { ds_poke(ds_blk, ' '); yyline++; }
286 <BLK>.                  { ds_poke(ds_blk, *yytext); }
288 =[ \t\n]*{BLOCKNAME}    {
289                                 /* block assignation */
290                                 yylval.p=yytext + 1;
292                                 /* skip (possible) spaces between
293                                    the = and the blockname; this lex
294                                    rule is written this way to avoid
295                                    having a global match for {BLOCKNAME},
296                                    that could swallow notes and such,
297                                    being mismatched as blocknames */
298                                 while(*yylval.p == ' ' ||
299                                       *yylval.p == '\n' ||
300                                       *yylval.p == '\t')
301                                         yylval.p++;
303                                 return(BLK_ASSIGN);
304                         }
305 \${BLOCKNAME}           {
306                                 /* block insertion */
307                                 yylval.p=yytext + 1;
308                                 return(BLK_INSERT);
309                         }
310 `.+`                    {
311                                 /* file inclusion */
312                                 yytext[yyleng - 1]='\0';
313                                 yylval.p=yytext + 1;
314                                 return(FILE_INSERT);
315                         }
317 .                       { return(*yytext); }
321 int yywrap(void) { return(1); }
323 char * ds_load(char * file)
325         struct ds s;
326         int c;
327         FILE * f;
329         if((f=path_fopen(file, "r")) == NULL)
330                 return(NULL);
332         ds_init(s);
334         while((c=fgetc(f)) != EOF)
335                 ds_poke(s, c);
337         ds_poke(s, '\0');
338         fclose(f);
340         return(s.d);
344 int push_code(char * code, int times, int dyn)
346         struct code_stack * cs;
348         if(code_stack_i == MAX_INPUTS)
349                 return(0);
351         code_stack_i++;
352         cs=&code_stack[code_stack_i];
354         cs->code=code;
355         cs->offset=0;
356         cs->times=times;
357         cs->dyn=dyn;
359         return(1);
363 int push_code_from_file(char * file)
365         char * c;
367         if((c=ds_load(file)) == NULL)
368                 return(0);
370         push_code(c, 1, 1);
371         return(1);
375 int code_getchar(void)
377         struct code_stack * cs;
378         int c='\0';
380         while(c == '\0' && code_stack_i > -1)
381         {
382                 /* get current char */
383                 cs=&code_stack[code_stack_i];
384                 c=cs->code[cs->offset++];
386                 /* end of code? */
387                 if(c == '\0')
388                 {
389                         /* decrease times */
390                         if(--cs->times)
391                         {
392                                 /* rewind */
393                                 cs->offset=0;
394                         }
395                         else
396                         {
397                                 /* free if needed */
398                                 if(cs->dyn)
399                                         free(cs->code);
401                                 /* move to previous */
402                                 code_stack_i--;
403                         }
405                         /* in any case, return a separator */
406                         c=' ';
407                 }
408         }
410         return(c);
414 int yy_input_for_flex(char * buf, int max)
416         buf[0]=code_getchar();
418         return(buf[0] == '\0' ? 0 : 1);