Rests and zero notes support added to lexer/parser.
[ahxm.git] / compiler.l
blob574958f227a011a49907fea6d53d52a9bd4bb9b7
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 <math.h>
30 #include "y.tab.h"
32 void yyerror(char * s);
34 /* redefinition of input function for GNU Flex */
35 #undef YY_INPUT
36 #define YY_INPUT(b,r,m) (r=yy_input_for_flex(b,m))
38 #define MAX_INPUTS 256
40 struct code_stack
42         char * code;    /* code string */
43         int offset;     /* current offset */
44         int times;      /* times to be fed to lexer/parser */
45         int dyn;        /* if set, free() after usage */
48 static struct code_stack _code_stack[MAX_INPUTS];
49 static int _code_stack_i=-1;
51 /* dynamic string manipulation macros */
52 #ifndef ds_init
53 struct ds { char * d; int p; int s; };
54 #define ds_init(x) do { x.d=(char *)0; x.p=x.s=0; } while(0)
55 #define ds_rewind(x) x.p=0;
56 #define ds_free(x) do { if(x.d) free(x.d); ds_init(x); } while(0)
57 #define ds_redim(x) do { if(x.p >= x.s) x.d=realloc(x.d, x.s += 32); } while(0)
58 #define ds_poke(x,c) do { ds_redim(x); x.d[x.p++]=c; } while(0)
59 #define ds_pokes(x,t) do { char *p=t; while(*p) ds_poke(x, *p++); } while(0)
60 #endif /* ds_init */
62 /* block dynstring */
63 static struct ds _blk;
65 /* count of parentheses */
66 static int _blk_i;
70 DIGIT           [0-9]
71 INTEGER         {DIGIT}+
72 REAL            {DIGIT}*[\.]?{DIGIT}+
73 OPERATOR        [~\*\./,@+#-]
74 INCDEC          [-+]+
76 NOTE_P          [a-g]
77 NOTE_O          [',]+
78 NOTE_T3         \/3
79 NOTE_T5         \/5
81 MARKNAME        [-a-zA-Z0-9_]+
82 NEW_MARK        \^{MARKNAME}
83 GOTO_MARK       @{MARKNAME}
84 ASSERT_MARK     !{MARKNAME}
86 BLOCKNAME       [-a-zA-Z0-9_]+
88 WSPACE          [ \t\n]+
89 COMMAND         [zrost\\$?<;>l:xTM|]
91 %x REM SS BLK
95 {INTEGER}               {
96                                 /* integers */
97                                 yylval.i=atoi(yytext);
98                                 return(INTEGER);
99                         }
100 {REAL}                  {
101                                 /* real numbers */
102                                 yylval.d=atof(yytext);
103                                 return(REAL);
104                         }
106 {COMMAND}               { return(*yytext); }
107 {OPERATOR}              { return(*yytext); }
109 {NOTE_P}                {
110                                 yylval.i=*yytext - 'a';
111                                 return(NOTE_P);
112                         }
113 {NOTE_O}                {
114                                 /* immediate octave changes */
115                                 int n;
116                                 yylval.i=0;
117                                 for(n=0;yytext[n];n++)
118                                         yylval.i +=
119                                         (yytext[n] == ',' ? -1 : 1);
121                                 return(NOTE_O);
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 {INCDEC}                {
143                                 /* sequence of + and - */
144                                 int n;
145                                 yylval.i=0;
146                                 for(n=0;yytext[n];n++)
147                                         yylval.i +=
148                                         (yytext[n] == '+' ? 1 : -1);
149                                 return(INCDEC);
150                         }
152 {WSPACE}                { ; /* ignore blanks */ }
154 \/\*                    { BEGIN REM; /* C-like comments */ }
155 <REM>\*\/               { BEGIN 0; }
156 <REM>.                  { ; /* drop anything inside a comment */ }
158 \{                      { BEGIN SS; /* start of software synth commands */ }
159 <SS>\"[^\"]*\"          {
160                                 /* double-quoted string */
161                                 yytext[yyleng - 1]='\0';
162                                 yylval.p=yytext + 1;
163                                 return(SS_STR);
164                         }
165 <SS>[-]?{INTEGER}       {
166                                 /* integers */
167                                 yylval.i=atoi(yytext);
168                                 return(INTEGER);
169                         }
170 <SS>{REAL}              {
171                                 /* real numbers */
172                                 yylval.d=atof(yytext);
173                                 return(REAL);
174                         }
175 <SS>{INTEGER}s          {
176                                 /* frame count, in seconds */
177                                 yytext[yyleng - 1]='\0';
178                                 yylval.i=atoi(yytext) * 44100;
179                                 return(SS_FRAMES);
180                         }
181 <SS>{INTEGER}ms         {
182                                 /* frame count, in milliseconds */
183                                 yytext[yyleng - 2]='\0';
184                                 yylval.i=(atoi(yytext) * 44100) / 1000;
185                                 return(SS_FRAMES);
186                         }
187 <SS>wav                 { return(SS_WAV); }
188 <SS>pat                 { return(SS_PAT); }
189 <SS>sustain             { return(SS_SUSTAIN); }
191 <SS>delay               { return(SS_EFF_DELAY); }
192 <SS>echo                { return(SS_EFF_ECHO); }
193 <SS>comb                { return(SS_EFF_COMB); }
194 <SS>allpass             { return(SS_EFF_ALLPASS); }
195 <SS>flanger             { return(SS_EFF_FLANGER); }
196 <SS>wobble              { return(SS_EFF_WOBBLE); }
197 <SS>square_wobble       { return(SS_EFF_SQWOBBLE); }
198 <SS>fader               { return(SS_EFF_FADER); }
200 <SS>\}                  { BEGIN 0; }
201 <SS>{WSPACE}            { ; /* ignore blanks */ }
202 <SS>.                   yyerror("<SS>LEX unknown character");
204 \(                      {
205                                 /* start of block */
206                                 ds_init(_blk);
207                                 _blk_i=1;
208                                 BEGIN BLK;
209                         }
210 <BLK>\(                 { _blk_i++; ds_poke(_blk, *yytext); }
211 <BLK>\)                 {
212                                 /* one parentheses less */
213                                 _blk_i--;
215                                 /* ok with block? */
216                                 if(_blk_i == 0)
217                                 {
218                                         ds_poke(_blk, '\0');
219                                         yylval.p=_blk.d;
221                                         BEGIN 0;
222                                         return(BLOCK);
223                                 }
224                                 else
225                                         ds_poke(_blk, ')');
226                         }
227 <BLK>.                  { ds_poke(_blk, *yytext); }
228 =[ \t\n]*{BLOCKNAME}    {
229                                 /* block assignation */
230                                 yylval.p=yytext + 1;
232                                 /* skip (possible) spaces between
233                                    the = and the blockname; this lex
234                                    rule is written this way to avoid
235                                    having a global match for {BLOCKNAME},
236                                    that could swallow notes and such,
237                                    being mismatched as blocknames */
238                                 while(*yylval.p == ' ' ||
239                                       *yylval.p == '\n' ||
240                                       *yylval.p == '\t')
241                                         yylval.p++;
243                                 return(BLK_ASSIGN);
244                         }
245 \${BLOCKNAME}           {
246                                 /* block insertion */
247                                 yylval.p=yytext + 1;
248                                 return(BLK_INSERT);
249                         }
250 \%[^ ]+                 {
251                                 /* file inclusion */
252                                 yylval.p=yytext + 1;
253                                 return(FILE_INSERT);
254                         }
256 .                       yyerror("LEX Unknown character");
260 int yywrap(void) { return(1); }
262 int push_code(char * code, int times, int dyn)
264         struct code_stack * cs;
266         if(_code_stack_i == MAX_INPUTS)
267                 return(0);
269         _code_stack_i++;
270         cs=&_code_stack[_code_stack_i];
272         cs->code=code;
273         cs->offset=0;
274         cs->times=times;
275         cs->dyn=dyn;
277         return(1);
281 int code_getchar(void)
283         struct code_stack * cs;
284         int c='\0';
286         while(c == '\0' && _code_stack_i > -1)
287         {
288                 /* get current char */
289                 cs=&_code_stack[_code_stack_i];
290                 c=cs->code[cs->offset++];
292                 /* end of code? */
293                 if(c == '\0')
294                 {
295                         /* decrease times */
296                         if(--cs->times)
297                         {
298                                 /* rewind */
299                                 cs->offset=0;
300                         }
301                         else
302                         {
303                                 /* free if needed */
304                                 if(cs->dyn)
305                                         free(cs->code);
307                                 /* move to previous */
308                                 _code_stack_i--;
309                         }
311                         /* in any case, return a separator */
312                         c='\n';
313                 }
314         }
316         return(c);
320 int yy_input_for_flex(char * buf, int max)
322         buf[0]=code_getchar();
324         return(buf[0] == '\0' ? 0 : 1);