Samples are internally stored in the -1..1 range instead of -32768..32767
[ahxm.git] / compiler.l
blob5ece738f9335914d3a6f04de7740f130749488cd
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 struct code_stack
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 */
55 #ifndef ds_init
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)
63 #endif /* ds_init */
65 /* block dynstring */
66 static struct ds ds_blk;
68 /* count of parentheses */
69 static int ds_blk_i;
71 /* line number */
72 int yyline = 0;
76 DIGIT           [0-9]
77 P_INTEGER       {DIGIT}+
78 S_INTEGER       [-+]{P_INTEGER}
79 P_REAL          {DIGIT}*[\.]?{DIGIT}+
80 S_REAL          [-+]{P_REAL}
82 NOTE_P          [a-g]
83 NOTE_T3         \/3
84 NOTE_T5         \/5
86 MARKNAME        [-a-zA-Z0-9_]+
87 NEW_MARK        \^{MARKNAME}
88 GOTO_MARK       @{MARKNAME}
89 ASSERT_MARK     !{MARKNAME}
91 BLOCKNAME       [-a-zA-Z0-9_]+
93 WSPACE          [ \t]+
95 %x REM XC REMXC BLK
99 {P_INTEGER}             {
100                                 /* integers without sign */
101                                 yylval.i = atoi(yytext);
102                                 return(P_INTEGER);
103                         }
104 {S_INTEGER}             {
105                                 /* signed integers */
106                                 yylval.i = atoi(yytext);
107                                 return(S_INTEGER);
108                         }
109 {P_REAL}                {
110                                 /* real numbers without sign */
111                                 yylval.d = atof(yytext);
112                                 return(P_REAL);
113                         }
114 {S_REAL}                {
115                                 /* signel real numbers */
116                                 yylval.d = atof(yytext);
117                                 return(S_REAL);
118                         }
120 {NOTE_P}                {
121                                 /* note pitch */
122                                 yylval.i = strchr(ascii_notes, *yytext) - ascii_notes;
123                                 return(NOTE_P);
124                         }
125 {NOTE_T3}               { return(NOTE_T3); }
126 {NOTE_T5}               { return(NOTE_T5); }
128 {NEW_MARK}              {
129                                 /* create new mark */
130                                 yylval.p = yytext + 1;
131                                 return(NEW_MARK);
132                         }
133 {GOTO_MARK}             {
134                                 /* go to mark */
135                                 yylval.p = yytext + 1;
136                                 return(GOTO_MARK);
137                         }
138 {ASSERT_MARK}           {
139                                 /* assert mark */
140                                 yylval.p = yytext + 1;
141                                 return(ASSERT_MARK);
142                         }
144 {WSPACE}                { ; /* ignore blanks */ }
146 \n                      { yyline++; }
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 */ }
154 <XC>\"[^\"]*\"          {
155                                 /* double-quoted string */
156                                 yytext[yyleng - 1] = '\0';
157                                 yylval.p = strdup(yytext + 1);
158                                 return(XC_STR);
159                         }
160 <XC>\'[^\']*\'          {
161                                 /* single-quoted string */
162                                 yytext[yyleng - 1] = '\0';
163                                 yylval.p = strdup(yytext + 1);
164                                 return(XC_STR);
165                         }
166 <XC>{P_INTEGER}         {
167                                 yylval.i = atoi(yytext);
168                                 return(P_INTEGER);
169                         }
170 <XC>{S_INTEGER}         {
171                                 yylval.i = atoi(yytext);
172                                 return(S_INTEGER);
173                         }
174 <XC>{P_REAL}            {
175                                 yylval.d = atof(yytext);
176                                 return(P_REAL);
177                         }
178 <XC>{S_REAL}            {
179                                 yylval.d = atof(yytext);
180                                 return(S_REAL);
181                         }
182 <XC>{P_REAL}s           {
183                                 /* frame count, in seconds */
184                                 yytext[yyleng - 1] = '\0';
185                                 yylval.d = atof(yytext) * 1000;
186                                 return(XC_MSECS);
187                         }
188 <XC>{P_REAL}ms          {
189                                 /* frame count, in milliseconds */
190                                 yytext[yyleng - 2] = '\0';
191                                 yylval.d = atof(yytext);
192                                 return(XC_MSECS);
193                         }
194 <XC>{NOTE_P}[\#\&]?{P_INTEGER} {
195                                 char * ptr = yytext;
197                                 /* process note */
198                                 yylval.i = strchr(ascii_notes, *ptr) - ascii_notes;
199                                 ptr++;
201                                 /* process optional sharps or flats */
202                                 if(*ptr == '#')
203                                 {
204                                         yylval.i++;
205                                         ptr++;
206                                 }
207                                 else
208                                 if(*ptr == '&')
209                                 {
210                                         yylval.i--;
211                                         ptr++;
212                                 }
214                                 /* process octave */
215                                 yylval.i += atoi(ptr) * 12;
217                                 return(XC_ABSNOTE);
218                         }
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++; }
251 <REMXC>.                { ; }
253 <XC>\}                  { BEGIN 0; }
254 <XC>{WSPACE}            { ; /* ignore blanks */ }
255 <XC>\n                  { yyline++; }
256 <XC>.                   { return(*yytext); }
258 \(                      {
259                                 /* start of block */
260                                 ds_init(ds_blk);
261                                 ds_blk_i = 1;
262                                 BEGIN BLK;
263                         }
264 <BLK>\(                 { ds_blk_i++; ds_poke(ds_blk, *yytext); }
265 <BLK>\)                 {
266                                 /* one parentheses less */
267                                 ds_blk_i--;
269                                 /* ok with block? */
270                                 if(ds_blk_i == 0)
271                                 {
272                                         ds_poke(ds_blk, '\0');
273                                         yylval.p = ds_blk.d;
275                                         BEGIN 0;
276                                         return(BLOCK);
277                                 }
278                                 else
279                                         ds_poke(ds_blk, ')');
280                         }
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 == ' ' ||
295                                       *yylval.p == '\n' ||
296                                       *yylval.p == '\t')
297                                         yylval.p++;
299                                 return(BLK_ASSIGN);
300                         }
301 \${BLOCKNAME}           {
302                                 /* block insertion */
303                                 yylval.p = yytext + 1;
304                                 return(BLK_INSERT);
305                         }
306 `.+`                    {
307                                 /* file inclusion */
308                                 yytext[yyleng - 1] = '\0';
309                                 yylval.p = yytext + 1;
310                                 return(FILE_INSERT);
311                         }
313 .                       { return(*yytext); }
317 int yywrap(void) { return(1); }
319 char * ds_load(char * file)
321         struct ds s;
322         int c;
323         FILE * f;
325         if((f = libpath_fopen(file, "r")) == NULL)
326                 return(NULL);
328         ds_init(s);
330         while((c = fgetc(f)) != EOF)
331                 ds_poke(s, c);
333         ds_poke(s, '\0');
334         fclose(f);
336         return(s.d);
340 int push_code(char * code)
342         struct code_stack * cs;
344         code_stack_i++;
345         GROW(code_stack, code_stack_i, struct code_stack);
347         cs = &code_stack[code_stack_i];
349         cs->code = code;
350         cs->offset = 0;
352         return(1);
356 int push_code_from_file(char * file)
358         char * c;
360         if((c = ds_load(file)) == NULL)
361                 return(0);
363         push_code(c);
364         return(1);
368 int code_getchar(void)
370         struct code_stack * cs;
371         int c = '\0';
373         while(c == '\0' && code_stack_i > -1)
374         {
375                 /* get current char */
376                 cs = &code_stack[code_stack_i];
377                 c = cs->code[cs->offset++];
379                 /* end of code? */
380                 if(c == '\0')
381                 {
382                         /* free */
383                         free(cs->code);
385                         /* move to previous */
386                         code_stack_i--;
388                         /* in any case, return a separator */
389                         c = ' ';
390                 }
391         }
393         return(c);
397 int yy_input_for_flex(char * buf, int max)
399         buf[0] = code_getchar();
401         return(buf[0] == '\0' ? 0 : 1);