input.c changed to ss_input.c (Closes: #1028).
[ahxm.git] / compiler.l
blob4265d42192a2e2025c4784542054d7f13ae686bb
1 %{
2 /*
4     Ann Hell Ex Machina - Music Software
5     Copyright (C) 2003/2005 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 /* the notes */
37 static char * ascii_notes="ccddeffggaab";
39 /* redefinition of input function for GNU Flex */
40 #undef YY_INPUT
41 #define YY_INPUT(b,r,m) (r=yy_input_for_flex(b,m))
43 #define MAX_INPUTS 256
45 struct code_stack
47         char * code;    /* code string */
48         int offset;     /* current offset */
49         int times;      /* times to be fed to lexer/parser */
50         int dyn;        /* if set, free() after usage */
53 static struct code_stack _code_stack[MAX_INPUTS];
54 static int _code_stack_i=-1;
56 /* dynamic string manipulation macros */
57 #ifndef ds_init
58 struct ds { char * d; int p; int s; };
59 #define ds_init(x) do { x.d=(char *)0; x.p=x.s=0; } while(0)
60 #define ds_rewind(x) x.p=0;
61 #define ds_free(x) do { if(x.d) free(x.d); ds_init(x); } while(0)
62 #define ds_redim(x) do { if(x.p >= x.s) x.d=realloc(x.d, x.s += 32); } while(0)
63 #define ds_poke(x,c) do { ds_redim(x); x.d[x.p++]=c; } while(0)
64 #define ds_pokes(x,t) do { char *p=t; while(*p) ds_poke(x, *p++); } while(0)
65 #endif /* ds_init */
67 /* block dynstring */
68 static struct ds _blk;
70 /* count of parentheses */
71 static int _blk_i;
73 /* line number */
74 int yyline=0;
78 DIGIT           [0-9]
79 P_INTEGER       {DIGIT}+
80 S_INTEGER       [-+]{P_INTEGER}
81 P_REAL          {DIGIT}*[\.]?{DIGIT}+
82 S_REAL          [-+]{P_REAL}
84 NOTE_P          [a-g]
85 NOTE_T3         \/3
86 NOTE_T5         \/5
88 MARKNAME        [-a-zA-Z0-9_]+
89 NEW_MARK        \^{MARKNAME}
90 GOTO_MARK       @{MARKNAME}
91 ASSERT_MARK     !{MARKNAME}
93 BLOCKNAME       [-a-zA-Z0-9_]+
95 WSPACE          [ \t]+
97 %x REM XC REMXC BLK
101 {P_INTEGER}             {
102                                 /* integers without sign */
103                                 yylval.i=atoi(yytext);
104                                 return(P_INTEGER);
105                         }
106 {S_INTEGER}             {
107                                 /* signed integers */
108                                 yylval.i=atoi(yytext);
109                                 return(S_INTEGER);
110                         }
111 {P_REAL}                {
112                                 /* real numbers without sign */
113                                 yylval.d=atof(yytext);
114                                 return(P_REAL);
115                         }
116 {S_REAL}                {
117                                 /* signel real numbers */
118                                 yylval.d=atof(yytext);
119                                 return(S_REAL);
120                         }
122 {NOTE_P}                {
123                                 /* note pitch */
124                                 yylval.i=strchr(ascii_notes, *yytext) - ascii_notes;
125                                 return(NOTE_P);
126                         }
127 {NOTE_T3}               { return(NOTE_T3); }
128 {NOTE_T5}               { return(NOTE_T5); }
130 {NEW_MARK}              {
131                                 /* create new mark */
132                                 yylval.p=yytext + 1;
133                                 return(NEW_MARK);
134                         }
135 {GOTO_MARK}             {
136                                 /* go to mark */
137                                 yylval.p=yytext + 1;
138                                 return(GOTO_MARK);
139                         }
140 {ASSERT_MARK}           {
141                                 /* assert mark */
142                                 yylval.p=yytext + 1;
143                                 return(ASSERT_MARK);
144                         }
146 {WSPACE}                { ; /* ignore blanks */ }
148 \n                      { yyline++; }
150 \/\*                    { BEGIN REM; /* C-like comments */ }
151 <REM>\*\/               { BEGIN 0; }
152 <REM>\n                 { yyline++; }
153 <REM>.                  { ; /* drop anything inside a comment */ }
155 \{                      { BEGIN XC; /* start of extended commands */ }
156 <XC>\"[^\"]*\"          {
157                                 /* double-quoted string */
158                                 yytext[yyleng - 1]='\0';
159                                 yylval.p=strdup(yytext + 1);
160                                 return(XC_STR);
161                         }
162 <XC>\'[^\']*\'          {
163                                 /* single-quoted string */
164                                 yytext[yyleng - 1]='\0';
165                                 yylval.p=strdup(yytext + 1);
166                                 return(XC_STR);
167                         }
168 <XC>{P_INTEGER}         {
169                                 yylval.i=atoi(yytext);
170                                 return(P_INTEGER);
171                         }
172 <XC>{S_INTEGER}         {
173                                 yylval.i=atoi(yytext);
174                                 return(S_INTEGER);
175                         }
176 <XC>{P_REAL}            {
177                                 yylval.d=atof(yytext);
178                                 return(P_REAL);
179                         }
180 <XC>{S_REAL}            {
181                                 yylval.d=atof(yytext);
182                                 return(S_REAL);
183                         }
184 <XC>{P_REAL}s           {
185                                 /* frame count, in seconds */
186                                 yytext[yyleng - 1]='\0';
187                                 yylval.i=atof(yytext) * 1000;
188                                 return(XC_MSECS);
189                         }
190 <XC>{P_INTEGER}ms       {
191                                 /* frame count, in milliseconds */
192                                 yytext[yyleng - 2]='\0';
193                                 yylval.i=atoi(yytext);
194                                 return(XC_MSECS);
195                         }
196 <XC>{NOTE_P}[\#\&]?{P_INTEGER} {
197                                 char * ptr=yytext;
199                                 /* process note */
200                                 yylval.i=strchr(ascii_notes, *ptr) - ascii_notes;
201                                 ptr++;
203                                 /* process optional sharps or flats */
204                                 if(*ptr == '#')
205                                 {
206                                         yylval.i++;
207                                         ptr++;
208                                 }
209                                 else
210                                 if(*ptr == '&')
211                                 {
212                                         yylval.i--;
213                                         ptr++;
214                                 }
216                                 /* process octave */
217                                 yylval.i += atoi(ptr) * 12;
219                                 return(XC_ABSNOTE);
220                         }
222 <XC>wav                 { return(SS_WAV); }
223 <XC>pat                 { return(SS_PAT); }
224 <XC>sustain             { return(SS_SUSTAIN); }
226 <XC>delay               { return(SS_EFF_DELAY); }
227 <XC>echo                { return(SS_EFF_ECHO); }
228 <XC>comb                { return(SS_EFF_COMB); }
229 <XC>allpass             { return(SS_EFF_ALLPASS); }
230 <XC>flanger             { return(SS_EFF_FLANGER); }
231 <XC>wobble              { return(SS_EFF_WOBBLE); }
232 <XC>square_wobble       { return(SS_EFF_SQWOBBLE); }
233 <XC>fader               { return(SS_EFF_FADER); }
234 <XC>reverb              { return(SS_EFF_REVERB); }
236 <XC>\/\*                { BEGIN REMXC; /* C-like comments inside XC */ }
237 <REMXC>\*\/             { BEGIN XC; /* jump back to XC processing */ }
238 <REMXC>\n               { yyline++; }
239 <REMXC>.                { ; }
241 <XC>\}                  { BEGIN 0; }
242 <XC>{WSPACE}            { ; /* ignore blanks */ }
243 <XC>\n                  { yyline++; }
244 <XC>.                   { return(*yytext); }
246 \(                      {
247                                 /* start of block */
248                                 ds_init(_blk);
249                                 _blk_i=1;
250                                 BEGIN BLK;
251                         }
252 <BLK>\(                 { _blk_i++; ds_poke(_blk, *yytext); }
253 <BLK>\)                 {
254                                 /* one parentheses less */
255                                 _blk_i--;
257                                 /* ok with block? */
258                                 if(_blk_i == 0)
259                                 {
260                                         ds_poke(_blk, '\0');
261                                         yylval.p=_blk.d;
263                                         BEGIN 0;
264                                         return(BLOCK);
265                                 }
266                                 else
267                                         ds_poke(_blk, ')');
268                         }
269 <BLK>\n                 { yyline++; }
270 <BLK>.                  { ds_poke(_blk, *yytext); }
272 =[ \t\n]*{BLOCKNAME}    {
273                                 /* block assignation */
274                                 yylval.p=yytext + 1;
276                                 /* skip (possible) spaces between
277                                    the = and the blockname; this lex
278                                    rule is written this way to avoid
279                                    having a global match for {BLOCKNAME},
280                                    that could swallow notes and such,
281                                    being mismatched as blocknames */
282                                 while(*yylval.p == ' ' ||
283                                       *yylval.p == '\n' ||
284                                       *yylval.p == '\t')
285                                         yylval.p++;
287                                 return(BLK_ASSIGN);
288                         }
289 \${BLOCKNAME}           {
290                                 /* block insertion */
291                                 yylval.p=yytext + 1;
292                                 return(BLK_INSERT);
293                         }
294 `.+`                    {
295                                 /* file inclusion */
296                                 yytext[yyleng - 1]='\0';
297                                 yylval.p=yytext + 1;
298                                 return(FILE_INSERT);
299                         }
301 .                       { return(*yytext); }
305 int yywrap(void) { return(1); }
307 char * ds_load(char * file)
309         struct ds s;
310         int c;
311         FILE * f;
313         if((f=fopen(file, "r")) == NULL)
314                 return(NULL);
316         ds_init(s);
318         while((c=fgetc(f)) != EOF)
319                 ds_poke(s, c);
321         ds_poke(s, '\0');
322         fclose(f);
324         return(s.d);
328 int push_code(char * code, int times, int dyn)
330         struct code_stack * cs;
332         if(_code_stack_i == MAX_INPUTS)
333                 return(0);
335         _code_stack_i++;
336         cs=&_code_stack[_code_stack_i];
338         cs->code=code;
339         cs->offset=0;
340         cs->times=times;
341         cs->dyn=dyn;
343         return(1);
347 int push_code_from_file(char * file)
349         char * c;
351         if((c=ds_load(file)) == NULL)
352                 return(0);
354         push_code(c, 1, 1);
355         return(1);
359 int code_getchar(void)
361         struct code_stack * cs;
362         int c='\0';
364         while(c == '\0' && _code_stack_i > -1)
365         {
366                 /* get current char */
367                 cs=&_code_stack[_code_stack_i];
368                 c=cs->code[cs->offset++];
370                 /* end of code? */
371                 if(c == '\0')
372                 {
373                         /* decrease times */
374                         if(--cs->times)
375                         {
376                                 /* rewind */
377                                 cs->offset=0;
378                         }
379                         else
380                         {
381                                 /* free if needed */
382                                 if(cs->dyn)
383                                         free(cs->code);
385                                 /* move to previous */
386                                 _code_stack_i--;
387                         }
389                         /* in any case, return a separator */
390                         c='\n';
391                 }
392         }
394         return(c);
398 int yy_input_for_flex(char * buf, int max)
400         buf[0]=code_getchar();
402         return(buf[0] == '\0' ? 0 : 1);