Add 'b' to all fopen modes.
[ahxm.git] / compiler.l
blob2c51550c18b579076fd53ea8fdd1f643b6d1a7dd
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; }
234 <XC>master_volume       { return SS_MASTER_VOL; }
236 <XC>delay               { return SS_EFF_DELAY; }
237 <XC>echo                { return SS_EFF_ECHO; }
238 <XC>comb                { return SS_EFF_COMB; }
239 <XC>allpass             { return SS_EFF_ALLPASS; }
240 <XC>flanger             { return SS_EFF_FLANGER; }
241 <XC>wobble              { return SS_EFF_WOBBLE; }
242 <XC>square_wobble       { return SS_EFF_SQWOBBLE; }
243 <XC>half_wobble         { return SS_EFF_HFWOBBLE; }
244 <XC>fader               { return SS_EFF_FADER; }
245 <XC>reverb              { return SS_EFF_REVERB; }
246 <XC>foldback            { return SS_EFF_FOLDBACK; }
247 <XC>atan                { return SS_EFF_ATAN; }
248 <XC>distort             { return SS_EFF_DISTORT; }
249 <XC>overdrive           { return SS_EFF_OVERDRIVE; }
250 <XC>off                 { return SS_EFF_OFF; }
252 <XC>pitch_stretch       { return SS_PITCH_STRETCH; }
253 <XC>time_stretch        { return SS_TIME_STRETCH; }
254 <XC>print_wave_tempo    { return SS_PRINT_WAVE_TEMPO; }
256 <XC>song_info           { return SONG_INFO; }
258 <XC>midi_channel        { return MIDI_CHANNEL; }
259 <XC>midi_program        { return MIDI_PROGRAM; }
260 <XC>midi_generic        { return MIDI_GENERIC; }
262 <XC>\/\*                { BEGIN REMXC; /* C-like comments inside XC */ }
263 <REMXC>\*\/             { BEGIN XC; /* jump back to XC processing */ }
264 <REMXC>\n               { yyline++; }
265 <REMXC>.                { ; }
267 <XC>\}                  { BEGIN 0; }
268 <XC>{WSPACE}            { ; /* ignore blanks */ }
269 <XC>\n                  { yyline++; }
270 <XC>.                   { return *yytext; }
272 \(                      {
273                                 /* start of block */
274                                 ds_init(ds_blk);
275                                 ds_blk_i = 1;
276                                 BEGIN BLK;
277                         }
278 <BLK>\(                 { ds_blk_i++; ds_poke(ds_blk, *yytext); }
279 <BLK>\)                 {
280                                 /* one parentheses less */
281                                 ds_blk_i--;
283                                 /* ok with block? */
284                                 if (ds_blk_i == 0) {
285                                         ds_poke(ds_blk, '\0');
286                                         yylval.p = ds_blk.d;
288                                         BEGIN 0;
289                                         return BLOCK;
290                                 }
291                                 else
292                                         ds_poke(ds_blk, ')');
293                         }
294 <BLK>\n                 { ds_poke(ds_blk, ' '); yyline++; }
295 <BLK>.                  { ds_poke(ds_blk, *yytext); }
297 =[ \t\n]*{BLOCKNAME}    {
298                                 /* block assignation */
299                                 yylval.p = yytext + 1;
301                                 /* skip (possible) spaces between
302                                    the = and the blockname; this lex
303                                    rule is written this way to avoid
304                                    having a global match for {BLOCKNAME},
305                                    that could swallow notes and such,
306                                    being mismatched as blocknames */
307                                 while (*yylval.p == ' ' ||
308                                       *yylval.p == '\n' ||
309                                       *yylval.p == '\t')
310                                         yylval.p++;
312                                 return BLK_ASSIGN;
313                         }
314 \${BLOCKNAME}           {
315                                 /* block insertion */
316                                 yylval.p = yytext + 1;
317                                 return BLK_INSERT;
318                         }
319 `.+`                    {
320                                 /* file inclusion */
321                                 yytext[yyleng - 1] = '\0';
322                                 yylval.p = yytext + 1;
323                                 return FILE_INSERT;
324                         }
325 L[^ \t\n]+              {
326                                 /* add libpath */
327                                 yylval.p = yytext + 1;
328                                 return LIBPATH_ADD;
329                         }
331 .                       { return *yytext; }
335 int yywrap(void) { return(1); }
337 char * ds_load(const char * file)
339         struct ds s;
340         int c;
341         FILE * f;
343         if ((f = libpath_fopen(file, "rb")) == NULL)
344                 return(NULL);
346         ds_init(s);
348         while ((c = fgetc(f)) != EOF)
349                 ds_poke(s, c);
351         ds_poke(s, '\0');
352         fclose(f);
354         return s.d;
358 int push_code(const char * code)
360         struct code_stack * cs;
362         code_stack_i++;
363         GROW(code_stack, code_stack_i, struct code_stack);
365         cs = &code_stack[code_stack_i];
367         cs->code = code;
368         cs->offset = 0;
370         return 1;
374 int push_code_from_file(const char * file)
376         char * c;
378         if ((c = ds_load(file)) == NULL)
379                 return 0;
381         push_code(c);
382         return 1;
386 int code_getchar(void)
388         struct code_stack * cs;
389         int c = '\0';
391         while (c == '\0' && code_stack_i > -1) {
392                 /* get current char */
393                 cs = &code_stack[code_stack_i];
394                 c = cs->code[cs->offset++];
396                 /* end of code? */
397                 if (c == '\0') {
398                         /* free */
399                         free((char *) cs->code);
401                         /* move to previous */
402                         code_stack_i--;
404                         /* in any case, return a separator */
405                         c = ' ';
406                 }
407         }
409         return c;
413 int yy_input_for_flex(char * buf, int max)
415         buf[0] = code_getchar();
417         return buf[0] == '\0' ? 0 : 1;