Added a new source file, ss_song.c, to hold the old "event2" stream,
[ahxm.git] / compiler.l
blob7172e2cd247e725b3a2416d1a1c1bcd65ed5c3cd
1 %{
2 /*
4     Ann Hell Ex Machina - Music Software
5     Copyright (C) 2003/2004 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 void yyerror(char * s);
34 int yy_input_for_flex(char * buf, int max);
36 /* redefinition of input function for GNU Flex */
37 #undef YY_INPUT
38 #define YY_INPUT(b,r,m) (r=yy_input_for_flex(b,m))
40 #define MAX_INPUTS 256
42 struct code_stack
44         char * code;    /* code string */
45         int offset;     /* current offset */
46         int times;      /* times to be fed to lexer/parser */
47         int dyn;        /* if set, free() after usage */
50 static struct code_stack _code_stack[MAX_INPUTS];
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 _blk;
67 /* count of parentheses */
68 static int _blk_i;
72 DIGIT           [0-9]
73 P_INTEGER       {DIGIT}+
74 S_INTEGER       [-+]{P_INTEGER}
75 P_REAL          {DIGIT}*[\.]?{DIGIT}+
76 S_REAL          [-+]{P_REAL}
78 NOTE_P          [a-g]
79 NOTE_T3         \/3
80 NOTE_T5         \/5
82 MARKNAME        [-a-zA-Z0-9_]+
83 NEW_MARK        \^{MARKNAME}
84 GOTO_MARK       @{MARKNAME}
85 ASSERT_MARK     !{MARKNAME}
87 BLOCKNAME       [-a-zA-Z0-9_]+
89 WSPACE          [ \t\n]+
91 %x REM XC BLK
95 {P_INTEGER}             {
96                                 /* integers without sign */
97                                 yylval.i=atoi(yytext);
98                                 return(P_INTEGER);
99                         }
100 {S_INTEGER}             {
101                                 /* signed integers */
102                                 yylval.i=atoi(yytext);
103                                 return(S_INTEGER);
104                         }
105 {P_REAL}                {
106                                 /* real numbers without sign */
107                                 yylval.d=atof(yytext);
108                                 return(P_REAL);
109                         }
110 {S_REAL}                {
111                                 /* signel real numbers */
112                                 yylval.d=atof(yytext);
113                                 return(S_REAL);
114                         }
116 {NOTE_P}                {
117                                 /* note pitch */
118                                 char * _notes="ccddeffggaab";
120                                 yylval.i=strchr(_notes, *yytext) - _notes;
121                                 return(NOTE_P);
122                         }
123 {NOTE_T3}               { return(NOTE_T3); }
124 {NOTE_T5}               { return(NOTE_T5); }
126 {NEW_MARK}              {
127                                 /* create new mark */
128                                 yylval.p=yytext + 1;
129                                 return(NEW_MARK);
130                         }
131 {GOTO_MARK}             {
132                                 /* go to mark */
133                                 yylval.p=yytext + 1;
134                                 return(GOTO_MARK);
135                         }
136 {ASSERT_MARK}           {
137                                 /* assert mark */
138                                 yylval.p=yytext + 1;
139                                 return(ASSERT_MARK);
140                         }
142 {WSPACE}                { ; /* ignore blanks */ }
144 \/\*                    { BEGIN REM; /* C-like comments */ }
145 <REM>\*\/               { BEGIN 0; }
146 <REM>.                  { ; /* drop anything inside a comment */ }
148 \{                      { BEGIN XC; /* start of extended commands */ }
149 <XC>\"[^\"]*\"          {
150                                 /* double-quoted string */
151                                 yytext[yyleng - 1]='\0';
152                                 yylval.p=yytext + 1;
153                                 return(XC_STR);
154                         }
155 <XC>{P_INTEGER}         {
156                                 yylval.i=atoi(yytext);
157                                 return(P_INTEGER);
158                         }
159 <XC>{S_INTEGER}         {
160                                 yylval.i=atoi(yytext);
161                                 return(S_INTEGER);
162                         }
163 <XC>{P_REAL}            {
164                                 yylval.d=atof(yytext);
165                                 return(P_REAL);
166                         }
167 <XC>{S_REAL}            {
168                                 yylval.d=atof(yytext);
169                                 return(S_REAL);
170                         }
171 <XC>{P_INTEGER}s        {
172                                 /* frame count, in seconds */
173                                 yytext[yyleng - 1]='\0';
174                                 yylval.i=atoi(yytext) * 1000;
175                                 return(XC_MSECS);
176                         }
177 <XC>{P_INTEGER}ms       {
178                                 /* frame count, in milliseconds */
179                                 yytext[yyleng - 2]='\0';
180                                 yylval.i=atoi(yytext);
181                                 return(XC_MSECS);
182                         }
183 <XC>wav                 { return(SS_WAV); }
184 <XC>pat                 { return(SS_PAT); }
185 <XC>sustain             { return(SS_SUSTAIN); }
187 <XC>delay               { return(SS_EFF_DELAY); }
188 <XC>echo                { return(SS_EFF_ECHO); }
189 <XC>comb                { return(SS_EFF_COMB); }
190 <XC>allpass             { return(SS_EFF_ALLPASS); }
191 <XC>flanger             { return(SS_EFF_FLANGER); }
192 <XC>wobble              { return(SS_EFF_WOBBLE); }
193 <XC>square_wobble       { return(SS_EFF_SQWOBBLE); }
194 <XC>fader               { return(SS_EFF_FADER); }
196 <XC>\}                  { BEGIN 0; }
197 <XC>{WSPACE}            { ; /* ignore blanks */ }
198 <XC>.                   { return(*yytext); }
200 \(                      {
201                                 /* start of block */
202                                 ds_init(_blk);
203                                 _blk_i=1;
204                                 BEGIN BLK;
205                         }
206 <BLK>\(                 { _blk_i++; ds_poke(_blk, *yytext); }
207 <BLK>\)                 {
208                                 /* one parentheses less */
209                                 _blk_i--;
211                                 /* ok with block? */
212                                 if(_blk_i == 0)
213                                 {
214                                         ds_poke(_blk, '\0');
215                                         yylval.p=_blk.d;
217                                         BEGIN 0;
218                                         return(BLOCK);
219                                 }
220                                 else
221                                         ds_poke(_blk, ')');
222                         }
223 <BLK>.                  { ds_poke(_blk, *yytext); }
225 =[ \t\n]*{BLOCKNAME}    {
226                                 /* block assignation */
227                                 yylval.p=yytext + 1;
229                                 /* skip (possible) spaces between
230                                    the = and the blockname; this lex
231                                    rule is written this way to avoid
232                                    having a global match for {BLOCKNAME},
233                                    that could swallow notes and such,
234                                    being mismatched as blocknames */
235                                 while(*yylval.p == ' ' ||
236                                       *yylval.p == '\n' ||
237                                       *yylval.p == '\t')
238                                         yylval.p++;
240                                 return(BLK_ASSIGN);
241                         }
242 \${BLOCKNAME}           {
243                                 /* block insertion */
244                                 yylval.p=yytext + 1;
245                                 return(BLK_INSERT);
246                         }
247 `.+`                    {
248                                 /* file inclusion */
249                                 yytext[yyleng - 1]='\0';
250                                 yylval.p=yytext + 1;
251                                 return(FILE_INSERT);
252                         }
254 .                       { return(*yytext); }
258 int yywrap(void) { return(1); }
260 char * ds_load(char * file)
262         struct ds s;
263         int c;
264         FILE * f;
266         if((f=fopen(file, "r")) == NULL)
267                 return(NULL);
269         ds_init(s);
271         while((c=fgetc(f)) != EOF)
272                 ds_poke(s, c);
274         ds_poke(s, '\0');
275         fclose(f);
277         return(s.d);
281 int push_code(char * code, int times, int dyn)
283         struct code_stack * cs;
285         if(_code_stack_i == MAX_INPUTS)
286                 return(0);
288         _code_stack_i++;
289         cs=&_code_stack[_code_stack_i];
291         cs->code=code;
292         cs->offset=0;
293         cs->times=times;
294         cs->dyn=dyn;
296         return(1);
300 int push_code_from_file(char * file)
302         char * c;
304         if((c=ds_load(file)) == NULL)
305                 return(0);
307         push_code(c, 1, 1);
308         return(1);
312 int code_getchar(void)
314         struct code_stack * cs;
315         int c='\0';
317         while(c == '\0' && _code_stack_i > -1)
318         {
319                 /* get current char */
320                 cs=&_code_stack[_code_stack_i];
321                 c=cs->code[cs->offset++];
323                 /* end of code? */
324                 if(c == '\0')
325                 {
326                         /* decrease times */
327                         if(--cs->times)
328                         {
329                                 /* rewind */
330                                 cs->offset=0;
331                         }
332                         else
333                         {
334                                 /* free if needed */
335                                 if(cs->dyn)
336                                         free(cs->code);
338                                 /* move to previous */
339                                 _code_stack_i--;
340                         }
342                         /* in any case, return a separator */
343                         c='\n';
344                 }
345         }
347         return(c);
351 int yy_input_for_flex(char * buf, int max)
353         buf[0]=code_getchar();
355         return(buf[0] == '\0' ? 0 : 1);