Added 'win32dist' Makefile target.
[ahxm.git] / compiler.l
bloba8b60926fd6e599cef913592988ffc16a1319ee9
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 {
56     char *d;
57     int p;
58     int s;
60 #define ds_init(x) do { x.d = (char *)0; x.p = x.s = 0; } while(0)
61 #define ds_rewind(x) x.p = 0;
62 #define ds_free(x) do { if (x.d) free(x.d); ds_init(x); } while(0)
63 #define ds_redim(x) do { if (x.p >= x.s) x.d = realloc(x.d, x.s += 32); } while(0)
64 #define ds_poke(x,c) do { ds_redim(x); x.d[x.p++] = c; } while(0)
65 #define ds_pokes(x,t) do { char *p = t; while (*p) ds_poke(x, *p++); } while(0)
66 #endif                          /* ds_init */
68 /* block dynstring */
69 static struct ds ds_blk;
71 /* count of parentheses */
72 static int ds_blk_i;
74 /* line number */
75 int yyline = 0;
79 DIGIT           [0-9]
80 P_INTEGER       {DIGIT}+
81 S_INTEGER       [-+]{P_INTEGER}
82 P_REAL          {DIGIT}*[\.]?{DIGIT}+
83 S_REAL          [-+]{P_REAL}
85 NOTE_P          [a-g]
86 NOTE_T3         \/3
87 NOTE_T5         \/5
89 MARKNAME        [-a-zA-Z0-9_]+
90 NEW_MARK        \^{MARKNAME}
91 GOTO_MARK       @{MARKNAME}
92 ASSERT_MARK     !{MARKNAME}
94 BLOCKNAME       [-a-zA-Z0-9_#&]+
96 WSPACE          [ \t]+
98 ALTSTR          A[-&#]*
100 %x REM XC REMXC BLK
104 {P_INTEGER}             {
105                                 /* integers without sign */
106                                 yylval.i = atoi(yytext);
107                                 return P_INTEGER;
108                         }
109 {S_INTEGER}             {
110                                 /* signed integers */
111                                 yylval.i = atoi(yytext);
112                                 return S_INTEGER;
113                         }
114 {P_REAL}                {
115                                 /* real numbers without sign */
116                                 yylval.d = atof(yytext);
117                                 return P_REAL;
118                         }
119 {S_REAL}                {
120                                 /* signel real numbers */
121                                 yylval.d = atof(yytext);
122                                 return S_REAL;
123                         }
125 {NOTE_P}                {
126                                 /* note pitch */
127                                 yylval.i = strchr(ascii_notes, *yytext) - ascii_notes;
128                                 return NOTE_P;
129                         }
130 {NOTE_T3}               { return NOTE_T3; }
131 {NOTE_T5}               { return NOTE_T5; }
133 {NEW_MARK}              {
134                                 /* create new mark */
135                                 yylval.p = yytext + 1;
136                                 return NEW_MARK;
137                         }
138 {GOTO_MARK}             {
139                                 /* go to mark */
140                                 yylval.p = yytext + 1;
141                                 return GOTO_MARK;
142                         }
143 {ASSERT_MARK}           {
144                                 /* assert mark */
145                                 yylval.p = yytext + 1;
146                                 return ASSERT_MARK;
147                         }
149 {ALTSTR}                {
150                                 /* alteration string */
151                                 yylval.p = yytext + 1;
152                                 return ALTSTR;
153                         }
155 {WSPACE}                { ; /* ignore blanks */ }
157 \n                      { yyline++; }
159 \/\*                    { BEGIN REM; /* C-like comments */ }
160 <REM>\*\/               { BEGIN 0; }
161 <REM>\n                 { yyline++; }
162 <REM>.                  { ; /* drop anything inside a comment */ }
164 \{                      { BEGIN XC; /* start of extended commands */ }
165 <XC>\"[^\"]*\"          {
166                                 /* double-quoted string */
167                                 yytext[yyleng - 1] = '\0';
168                                 yylval.p = strdup(yytext + 1);
169                                 return XC_STR;
170                         }
171 <XC>\'[^\']*\'          {
172                                 /* single-quoted string */
173                                 yytext[yyleng - 1] = '\0';
174                                 yylval.p = strdup(yytext + 1);
175                                 return XC_STR;
176                         }
177 <XC>{P_INTEGER}         {
178                                 yylval.i = atoi(yytext);
179                                 return P_INTEGER;
180                         }
181 <XC>{S_INTEGER}         {
182                                 yylval.i = atoi(yytext);
183                                 return S_INTEGER;
184                         }
185 <XC>{P_REAL}            {
186                                 yylval.d = atof(yytext);
187                                 return P_REAL;
188                         }
189 <XC>{S_REAL}            {
190                                 yylval.d = atof(yytext);
191                                 return S_REAL;
192                         }
193 <XC>{P_REAL}s           {
194                                 /* frame count, in seconds */
195                                 yytext[yyleng - 1] = '\0';
196                                 yylval.d = atof(yytext) * 1000;
197                                 return XC_MSECS;
198                         }
199 <XC>{P_REAL}ms          {
200                                 /* frame count, in milliseconds */
201                                 yytext[yyleng - 2] = '\0';
202                                 yylval.d = atof(yytext);
203                                 return XC_MSECS;
204                         }
205 <XC>{NOTE_P}[\#\&]?{P_INTEGER} {
206                                 char *ptr = yytext;
208                                 /* process note */
209                                 yylval.i = strchr(ascii_notes, *ptr) - ascii_notes;
210                                 ptr++;
212                                 /* process optional sharps or flats */
213                                 if (*ptr == '#') {
214                                         yylval.i++;
215                                         ptr++;
216                                 }
217                                 else
218                                 if (*ptr == '&') {
219                                         yylval.i--;
220                                         ptr++;
221                                 }
223                                 /* process octave */
224                                 yylval.i += atoi(ptr) * 12;
226                                 return XC_ABSNOTE;
227                         }
229 <XC>wav                 { return SS_WAV; }
230 <XC>pat                 { return SS_PAT; }
231 <XC>sf2                 { return SS_SF2; }
232 <XC>sustain             { return SS_SUSTAIN; }
233 <XC>attack              { return SS_ATTACK; }
234 <XC>vibrato             { return SS_VIBRATO; }
235 <XC>portamento          { return SS_PORTAMENTO; }
236 <XC>channel             { return SS_CHANNEL; }
237 <XC>vol                 { return SS_VOL; }
238 <XC>master_volume       { return SS_MASTER_VOL; }
240 <XC>delay               { return SS_EFF_DELAY; }
241 <XC>echo                { return SS_EFF_ECHO; }
242 <XC>comb                { return SS_EFF_COMB; }
243 <XC>allpass             { return SS_EFF_ALLPASS; }
244 <XC>flanger             { return SS_EFF_FLANGER; }
245 <XC>wobble              { return SS_EFF_WOBBLE; }
246 <XC>square_wobble       { return SS_EFF_SQWOBBLE; }
247 <XC>half_wobble         { return SS_EFF_HFWOBBLE; }
248 <XC>fader               { return SS_EFF_FADER; }
249 <XC>reverb              { return SS_EFF_REVERB; }
250 <XC>foldback            { return SS_EFF_FOLDBACK; }
251 <XC>atan                { return SS_EFF_ATAN; }
252 <XC>distort             { return SS_EFF_DISTORT; }
253 <XC>overdrive           { return SS_EFF_OVERDRIVE; }
254 <XC>off                 { return SS_EFF_OFF; }
256 <XC>pitch_stretch       { return SS_PITCH_STRETCH; }
257 <XC>time_stretch        { return SS_TIME_STRETCH; }
258 <XC>print_wave_tempo    { return SS_PRINT_WAVE_TEMPO; }
260 <XC>song_info           { return SONG_INFO; }
262 <XC>midi_channel        { return MIDI_CHANNEL; }
263 <XC>midi_program        { return MIDI_PROGRAM; }
264 <XC>midi_generic        { return MIDI_GENERIC; }
266 <XC>\/\*                { BEGIN REMXC; /* C-like comments inside XC */ }
267 <REMXC>\*\/             { BEGIN XC; /* jump back to XC processing */ }
268 <REMXC>\n               { yyline++; }
269 <REMXC>.                { ; }
271 <XC>\}                  { BEGIN 0; }
272 <XC>{WSPACE}            { ; /* ignore blanks */ }
273 <XC>\n                  { yyline++; }
274 <XC>.                   { return *yytext; }
276 \(                      {
277                                 /* start of block */
278                                 ds_init(ds_blk);
279                                 ds_blk_i = 1;
280                                 BEGIN BLK;
281                         }
282 <BLK>\(                 { ds_blk_i++; ds_poke(ds_blk, *yytext); }
283 <BLK>\)                 {
284                                 /* one parentheses less */
285                                 ds_blk_i--;
287                                 /* ok with block? */
288                                 if (ds_blk_i == 0) {
289                                         ds_poke(ds_blk, '\0');
290                                         yylval.p = ds_blk.d;
292                                         BEGIN 0;
293                                         return BLOCK;
294                                 }
295                                 else
296                                         ds_poke(ds_blk, ')');
297                         }
298 <BLK>\n                 { ds_poke(ds_blk, ' '); yyline++; }
299 <BLK>.                  { ds_poke(ds_blk, *yytext); }
301 =[ \t\n]*{BLOCKNAME}    {
302                                 /* block assignation */
303                                 yylval.p = yytext + 1;
305                                 /* skip (possible) spaces between
306                                    the = and the blockname; this lex
307                                    rule is written this way to avoid
308                                    having a global match for {BLOCKNAME},
309                                    that could swallow notes and such,
310                                    being mismatched as blocknames */
311                                 while (*yylval.p == ' ' ||
312                                       *yylval.p == '\n' ||
313                                       *yylval.p == '\t')
314                                         yylval.p++;
316                                 return BLK_ASSIGN;
317                         }
318 \${BLOCKNAME}           {
319                                 /* block insertion */
320                                 yylval.p = yytext + 1;
321                                 return BLK_INSERT;
322                         }
323 `.+`                    {
324                                 /* file inclusion */
325                                 yytext[yyleng - 1] = '\0';
326                                 yylval.p = yytext + 1;
327                                 return FILE_INSERT;
328                         }
329 L[^ \t\n]+              {
330                                 /* add libpath */
331                                 yylval.p = yytext + 1;
332                                 return LIBPATH_ADD;
333                         }
335 .                       { return *yytext; }
339 int yywrap(void)
341     return 1;
344 char *ds_load(const char *file)
346     struct ds s;
347     int c;
348     FILE *f;
350     if ((f = libpath_fopen(file, "rb")) == NULL)
351         return (NULL);
353     ds_init(s);
355     while ((c = fgetc(f)) != EOF)
356         ds_poke(s, c);
358     ds_poke(s, '\0');
359     fclose(f);
361     return s.d;
365 int push_code(const char *code)
367     struct code_stack *cs;
369     code_stack_i++;
370     GROW(code_stack, code_stack_i, struct code_stack);
372     cs = &code_stack[code_stack_i];
374     cs->code = code;
375     cs->offset = 0;
377     return 1;
381 int push_code_from_file(const char *file)
383     char *c;
385     if ((c = ds_load(file)) == NULL)
386         return 0;
388     push_code(c);
389     return 1;
393 int code_getchar(void)
395     struct code_stack *cs;
396     int c = '\0';
398     while (c == '\0' && code_stack_i > -1) {
399         /* get current char */
400         cs = &code_stack[code_stack_i];
401         c = cs->code[cs->offset++];
403         /* end of code? */
404         if (c == '\0') {
405             /* free */
406             free((char *) cs->code);
408             /* move to previous */
409             code_stack_i--;
411             /* in any case, return a separator */
412             c = ' ';
413         }
414     }
416     return c;
420 int yy_input_for_flex(char *buf, int max)
422     buf[0] = code_getchar();
424     return buf[0] == '\0' ? 0 : 1;