Fail if an iname is requested but is not found in ss_load_sf2_file().
[ahxm.git] / compiler.l
bloba730df361da400b2ff63797764dc494427ad4377
1 %{
2 /*
4     Ann Hell Ex Machina - Music Software
5     Copyright (C) 2003/2008 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 "ahxm.h"
35 void yyerror(const char *s);
36 int yy_input_for_flex(char * buf, int max);
38 /* the notes */
39 static const 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 {
46         const char *code;       /* code string */
47         int offset;             /* current offset */
50 static struct code_stack *code_stack = NULL;
51 static int code_stack_i = -1;
53 /* dynamic string manipulation macros */
54 #ifndef ds_init
55 struct ds { char *d; int p; int s; };
56 #define ds_init(x) do { x.d = (char *)0; x.p = x.s = 0; } while(0)
57 #define ds_rewind(x) x.p = 0;
58 #define ds_free(x) do { if (x.d) free(x.d); ds_init(x); } while(0)
59 #define ds_redim(x) do { if (x.p >= x.s) x.d = realloc(x.d, x.s += 32); } while(0)
60 #define ds_poke(x,c) do { ds_redim(x); x.d[x.p++] = c; } while(0)
61 #define ds_pokes(x,t) do { char *p = t; while (*p) ds_poke(x, *p++); } while(0)
62 #endif /* ds_init */
64 /* block dynstring */
65 static struct ds ds_blk;
67 /* count of parentheses */
68 static int ds_blk_i;
70 /* line number */
71 int yyline = 0;
75 DIGIT           [0-9]
76 P_INTEGER       {DIGIT}+
77 S_INTEGER       [-+]{P_INTEGER}
78 P_REAL          {DIGIT}*[\.]?{DIGIT}+
79 S_REAL          [-+]{P_REAL}
81 NOTE_P          [a-g]
82 NOTE_T3         \/3
83 NOTE_T5         \/5
85 MARKNAME        [-a-zA-Z0-9_]+
86 NEW_MARK        \^{MARKNAME}
87 GOTO_MARK       @{MARKNAME}
88 ASSERT_MARK     !{MARKNAME}
90 BLOCKNAME       [-a-zA-Z0-9_#&]+
92 WSPACE          [ \t]+
94 ALTSTR          A[-&#]*
96 %x REM XC REMXC BLK
100 {P_INTEGER}             {
101                                 /* integers without sign */
102                                 yylval.i = atoi(yytext);
103                                 return P_INTEGER;
104                         }
105 {S_INTEGER}             {
106                                 /* signed integers */
107                                 yylval.i = atoi(yytext);
108                                 return S_INTEGER;
109                         }
110 {P_REAL}                {
111                                 /* real numbers without sign */
112                                 yylval.d = atof(yytext);
113                                 return P_REAL;
114                         }
115 {S_REAL}                {
116                                 /* signel real numbers */
117                                 yylval.d = atof(yytext);
118                                 return S_REAL;
119                         }
121 {NOTE_P}                {
122                                 /* note pitch */
123                                 yylval.i = strchr(ascii_notes, *yytext) - ascii_notes;
124                                 return NOTE_P;
125                         }
126 {NOTE_T3}               { return NOTE_T3; }
127 {NOTE_T5}               { return NOTE_T5; }
129 {NEW_MARK}              {
130                                 /* create new mark */
131                                 yylval.p = yytext + 1;
132                                 return NEW_MARK;
133                         }
134 {GOTO_MARK}             {
135                                 /* go to mark */
136                                 yylval.p = yytext + 1;
137                                 return GOTO_MARK;
138                         }
139 {ASSERT_MARK}           {
140                                 /* assert mark */
141                                 yylval.p = yytext + 1;
142                                 return ASSERT_MARK;
143                         }
145 {ALTSTR}                {
146                                 /* alteration string */
147                                 yylval.p = yytext + 1;
148                                 return ALTSTR;
149                         }
151 {WSPACE}                { ; /* ignore blanks */ }
153 \n                      { yyline++; }
155 \/\*                    { BEGIN REM; /* C-like comments */ }
156 <REM>\*\/               { BEGIN 0; }
157 <REM>\n                 { yyline++; }
158 <REM>.                  { ; /* drop anything inside a comment */ }
160 \{                      { BEGIN XC; /* start of extended commands */ }
161 <XC>\"[^\"]*\"          {
162                                 /* double-quoted string */
163                                 yytext[yyleng - 1] = '\0';
164                                 yylval.p = strdup(yytext + 1);
165                                 return XC_STR;
166                         }
167 <XC>\'[^\']*\'          {
168                                 /* single-quoted string */
169                                 yytext[yyleng - 1] = '\0';
170                                 yylval.p = strdup(yytext + 1);
171                                 return XC_STR;
172                         }
173 <XC>{P_INTEGER}         {
174                                 yylval.i = atoi(yytext);
175                                 return P_INTEGER;
176                         }
177 <XC>{S_INTEGER}         {
178                                 yylval.i = atoi(yytext);
179                                 return S_INTEGER;
180                         }
181 <XC>{P_REAL}            {
182                                 yylval.d = atof(yytext);
183                                 return P_REAL;
184                         }
185 <XC>{S_REAL}            {
186                                 yylval.d = atof(yytext);
187                                 return S_REAL;
188                         }
189 <XC>{P_REAL}s           {
190                                 /* frame count, in seconds */
191                                 yytext[yyleng - 1] = '\0';
192                                 yylval.d = atof(yytext) * 1000;
193                                 return XC_MSECS;
194                         }
195 <XC>{P_REAL}ms          {
196                                 /* frame count, in milliseconds */
197                                 yytext[yyleng - 2] = '\0';
198                                 yylval.d = atof(yytext);
199                                 return XC_MSECS;
200                         }
201 <XC>{NOTE_P}[\#\&]?{P_INTEGER} {
202                                 char *ptr = yytext;
204                                 /* process note */
205                                 yylval.i = strchr(ascii_notes, *ptr) - ascii_notes;
206                                 ptr++;
208                                 /* process optional sharps or flats */
209                                 if (*ptr == '#') {
210                                         yylval.i++;
211                                         ptr++;
212                                 }
213                                 else
214                                 if (*ptr == '&') {
215                                         yylval.i--;
216                                         ptr++;
217                                 }
219                                 /* process octave */
220                                 yylval.i += atoi(ptr) * 12;
222                                 return XC_ABSNOTE;
223                         }
225 <XC>wav                 { return SS_WAV; }
226 <XC>pat                 { return SS_PAT; }
227 <XC>sf2                 { return SS_SF2; }
228 <XC>sustain             { return SS_SUSTAIN; }
229 <XC>attack              { return SS_ATTACK; }
230 <XC>vibrato             { return SS_VIBRATO; }
231 <XC>portamento          { return SS_PORTAMENTO; }
232 <XC>channel             { return SS_CHANNEL; }
233 <XC>vol                 { return SS_VOL; }
235 <XC>delay               { return SS_EFF_DELAY; }
236 <XC>echo                { return SS_EFF_ECHO; }
237 <XC>comb                { return SS_EFF_COMB; }
238 <XC>allpass             { return SS_EFF_ALLPASS; }
239 <XC>flanger             { return SS_EFF_FLANGER; }
240 <XC>wobble              { return SS_EFF_WOBBLE; }
241 <XC>square_wobble       { return SS_EFF_SQWOBBLE; }
242 <XC>half_wobble         { return SS_EFF_HFWOBBLE; }
243 <XC>fader               { return SS_EFF_FADER; }
244 <XC>reverb              { return SS_EFF_REVERB; }
245 <XC>foldback            { return SS_EFF_FOLDBACK; }
246 <XC>atan                { return SS_EFF_ATAN; }
247 <XC>distort             { return SS_EFF_DISTORT; }
248 <XC>overdrive           { return SS_EFF_OVERDRIVE; }
249 <XC>off                 { return SS_EFF_OFF; }
251 <XC>pitch_stretch       { return SS_PITCH_STRETCH; }
252 <XC>time_stretch        { return SS_TIME_STRETCH; }
253 <XC>print_wave_tempo    { return SS_PRINT_WAVE_TEMPO; }
255 <XC>song_info           { return SONG_INFO; }
257 <XC>midi_channel        { return MIDI_CHANNEL; }
258 <XC>midi_program        { return MIDI_PROGRAM; }
259 <XC>midi_generic        { return MIDI_GENERIC; }
261 <XC>\/\*                { BEGIN REMXC; /* C-like comments inside XC */ }
262 <REMXC>\*\/             { BEGIN XC; /* jump back to XC processing */ }
263 <REMXC>\n               { yyline++; }
264 <REMXC>.                { ; }
266 <XC>\}                  { BEGIN 0; }
267 <XC>{WSPACE}            { ; /* ignore blanks */ }
268 <XC>\n                  { yyline++; }
269 <XC>.                   { return *yytext; }
271 \(                      {
272                                 /* start of block */
273                                 ds_init(ds_blk);
274                                 ds_blk_i = 1;
275                                 BEGIN BLK;
276                         }
277 <BLK>\(                 { ds_blk_i++; ds_poke(ds_blk, *yytext); }
278 <BLK>\)                 {
279                                 /* one parentheses less */
280                                 ds_blk_i--;
282                                 /* ok with block? */
283                                 if (ds_blk_i == 0) {
284                                         ds_poke(ds_blk, '\0');
285                                         yylval.p = ds_blk.d;
287                                         BEGIN 0;
288                                         return BLOCK;
289                                 }
290                                 else
291                                         ds_poke(ds_blk, ')');
292                         }
293 <BLK>\n                 { ds_poke(ds_blk, ' '); yyline++; }
294 <BLK>.                  { ds_poke(ds_blk, *yytext); }
296 =[ \t\n]*{BLOCKNAME}    {
297                                 /* block assignation */
298                                 yylval.p = yytext + 1;
300                                 /* skip (possible) spaces between
301                                    the = and the blockname; this lex
302                                    rule is written this way to avoid
303                                    having a global match for {BLOCKNAME},
304                                    that could swallow notes and such,
305                                    being mismatched as blocknames */
306                                 while (*yylval.p == ' ' ||
307                                       *yylval.p == '\n' ||
308                                       *yylval.p == '\t')
309                                         yylval.p++;
311                                 return BLK_ASSIGN;
312                         }
313 \${BLOCKNAME}           {
314                                 /* block insertion */
315                                 yylval.p = yytext + 1;
316                                 return BLK_INSERT;
317                         }
318 `.+`                    {
319                                 /* file inclusion */
320                                 yytext[yyleng - 1] = '\0';
321                                 yylval.p = yytext + 1;
322                                 return FILE_INSERT;
323                         }
325 .                       { return *yytext; }
329 int yywrap(void) { return(1); }
331 char * ds_load(const char * file)
333         struct ds s;
334         int c;
335         FILE * f;
337         if ((f = libpath_fopen(file, "r")) == NULL)
338                 return(NULL);
340         ds_init(s);
342         while ((c = fgetc(f)) != EOF)
343                 ds_poke(s, c);
345         ds_poke(s, '\0');
346         fclose(f);
348         return s.d;
352 int push_code(const char * code)
354         struct code_stack * cs;
356         code_stack_i++;
357         GROW(code_stack, code_stack_i, struct code_stack);
359         cs = &code_stack[code_stack_i];
361         cs->code = code;
362         cs->offset = 0;
364         return 1;
368 int push_code_from_file(const char * file)
370         char * c;
372         if ((c = ds_load(file)) == NULL)
373                 return 0;
375         push_code(c);
376         return 1;
380 int code_getchar(void)
382         struct code_stack * cs;
383         int c = '\0';
385         while (c == '\0' && code_stack_i > -1) {
386                 /* get current char */
387                 cs = &code_stack[code_stack_i];
388                 c = cs->code[cs->offset++];
390                 /* end of code? */
391                 if (c == '\0') {
392                         /* free */
393                         free((char *) cs->code);
395                         /* move to previous */
396                         code_stack_i--;
398                         /* in any case, return a separator */
399                         c = ' ';
400                 }
401         }
403         return c;
407 int yy_input_for_flex(char * buf, int max)
409         buf[0] = code_getchar();
411         return buf[0] == '\0' ? 0 : 1;