SIGSEGV crashes seem fixed (Closes: #1145).
[ahxm.git] / compiler.l
bloba87bdb9775055e089598d5a803f49fca3eb59206
1 %{
2 /*
4     Ann Hell Ex Machina - Music Software
5     Copyright (C) 2003/2007 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(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 {
46         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>sustain             { return SS_SUSTAIN; }
228 <XC>attack              { return SS_ATTACK; }
229 <XC>vibrato             { return SS_VIBRATO; }
230 <XC>portamento          { return SS_PORTAMENTO; }
231 <XC>channel             { return SS_CHANNEL; }
232 <XC>vol                 { return SS_VOL; }
234 <XC>delay               { return SS_EFF_DELAY; }
235 <XC>echo                { return SS_EFF_ECHO; }
236 <XC>comb                { return SS_EFF_COMB; }
237 <XC>allpass             { return SS_EFF_ALLPASS; }
238 <XC>flanger             { return SS_EFF_FLANGER; }
239 <XC>wobble              { return SS_EFF_WOBBLE; }
240 <XC>square_wobble       { return SS_EFF_SQWOBBLE; }
241 <XC>half_wobble         { return SS_EFF_HFWOBBLE; }
242 <XC>fader               { return SS_EFF_FADER; }
243 <XC>reverb              { return SS_EFF_REVERB; }
244 <XC>foldback            { return SS_EFF_FOLDBACK; }
245 <XC>atan                { return SS_EFF_ATAN; }
246 <XC>distort             { return SS_EFF_DISTORT; }
247 <XC>overdrive           { return SS_EFF_OVERDRIVE; }
248 <XC>off                 { return SS_EFF_OFF; }
250 <XC>pitch_stretch       { return SS_PITCH_STRETCH; }
251 <XC>time_stretch        { return SS_TIME_STRETCH; }
252 <XC>print_wave_tempo    { return SS_PRINT_WAVE_TEMPO; }
254 <XC>song_info           { return SONG_INFO; }
256 <XC>midi_channel        { return MIDI_CHANNEL; }
257 <XC>midi_program        { return MIDI_PROGRAM; }
258 <XC>midi_generic        { return MIDI_GENERIC; }
260 <XC>\/\*                { BEGIN REMXC; /* C-like comments inside XC */ }
261 <REMXC>\*\/             { BEGIN XC; /* jump back to XC processing */ }
262 <REMXC>\n               { yyline++; }
263 <REMXC>.                { ; }
265 <XC>\}                  { BEGIN 0; }
266 <XC>{WSPACE}            { ; /* ignore blanks */ }
267 <XC>\n                  { yyline++; }
268 <XC>.                   { return *yytext; }
270 \(                      {
271                                 /* start of block */
272                                 ds_init(ds_blk);
273                                 ds_blk_i = 1;
274                                 BEGIN BLK;
275                         }
276 <BLK>\(                 { ds_blk_i++; ds_poke(ds_blk, *yytext); }
277 <BLK>\)                 {
278                                 /* one parentheses less */
279                                 ds_blk_i--;
281                                 /* ok with block? */
282                                 if (ds_blk_i == 0) {
283                                         ds_poke(ds_blk, '\0');
284                                         yylval.p = ds_blk.d;
286                                         BEGIN 0;
287                                         return BLOCK;
288                                 }
289                                 else
290                                         ds_poke(ds_blk, ')');
291                         }
292 <BLK>\n                 { ds_poke(ds_blk, ' '); yyline++; }
293 <BLK>.                  { ds_poke(ds_blk, *yytext); }
295 =[ \t\n]*{BLOCKNAME}    {
296                                 /* block assignation */
297                                 yylval.p = yytext + 1;
299                                 /* skip (possible) spaces between
300                                    the = and the blockname; this lex
301                                    rule is written this way to avoid
302                                    having a global match for {BLOCKNAME},
303                                    that could swallow notes and such,
304                                    being mismatched as blocknames */
305                                 while (*yylval.p == ' ' ||
306                                       *yylval.p == '\n' ||
307                                       *yylval.p == '\t')
308                                         yylval.p++;
310                                 return BLK_ASSIGN;
311                         }
312 \${BLOCKNAME}           {
313                                 /* block insertion */
314                                 yylval.p = yytext + 1;
315                                 return BLK_INSERT;
316                         }
317 `.+`                    {
318                                 /* file inclusion */
319                                 yytext[yyleng - 1] = '\0';
320                                 yylval.p = yytext + 1;
321                                 return FILE_INSERT;
322                         }
324 .                       { return *yytext; }
328 int yywrap(void) { return(1); }
330 char * ds_load(char * file)
332         struct ds s;
333         int c;
334         FILE * f;
336         if ((f = libpath_fopen(file, "r")) == NULL)
337                 return(NULL);
339         ds_init(s);
341         while ((c = fgetc(f)) != EOF)
342                 ds_poke(s, c);
344         ds_poke(s, '\0');
345         fclose(f);
347         return s.d;
351 int push_code(char * code)
353         struct code_stack * cs;
355         code_stack_i++;
356         GROW(code_stack, code_stack_i, struct code_stack);
358         cs = &code_stack[code_stack_i];
360         cs->code = code;
361         cs->offset = 0;
363         return 1;
367 int push_code_from_file(char * file)
369         char * c;
371         if ((c = ds_load(file)) == NULL)
372                 return 0;
374         push_code(c);
375         return 1;
379 int code_getchar(void)
381         struct code_stack * cs;
382         int c = '\0';
384         while (c == '\0' && code_stack_i > -1) {
385                 /* get current char */
386                 cs = &code_stack[code_stack_i];
387                 c = cs->code[cs->offset++];
389                 /* end of code? */
390                 if (c == '\0') {
391                         /* free */
392                         free(cs->code);
394                         /* move to previous */
395                         code_stack_i--;
397                         /* in any case, return a separator */
398                         c = ' ';
399                 }
400         }
402         return c;
406 int yy_input_for_flex(char * buf, int max)
408         buf[0] = code_getchar();
410         return buf[0] == '\0' ? 0 : 1;