lilypond-1.0.8
[lilypond.git] / mi2mu / midi-lexer.l
blob485312b974627fc70728435fce449ce207d9bc18
1 %{//-*-Fundamental-*-
2 // midi-lexer.l
4 /* 
5   yes, i know that midi is not really a (n evolving?) language,
6   and that using lex/yacc to parse midi is overkill, as well as
7   a grand example of misuse and asking for performance loss.
9   it is, however, quite robust, simple, and very easy to extend
10   incrementally.
11  */
14   backup rules
16   after making a change to the lexer rules, run 
17       flex -b <this lexer file>
18   and make sure that 
19       lex.backup
20   contains no backup states, but only the reminder
21       Compressed tables always back up.
22   (don-t forget to rm lex.yy.cc :-)
23  */
25 #include "string-convert.hh"
26 #include "mi2mu-global.hh"
27 #include "mi2mu-proto.hh"
28 #include "my-midi-lexer.hh"
29 #include "midi-parser.hh"
31 #define YY_USER_ACTION char_count_ += YYLeng(); // ugh
35 %option c++
36 %option noyywrap
37 %option nodefault
38 %option debug
39 %option yyclass="My_midi_lexer"
40 %option stack
42 %x data
43 %x event
44 %x i8
45 %x u8
46 %x int16
47 %x int32
48 %x meta_event
49 %x track
51 U8              [\x00-\xff]
52 I8              {U8}
53 INT16           {U8}{U8}
54 BACKUP_INT16_0  {U8}
55 INT32           {INT16}{INT16}
56 BACKUP_INT32_0  {U8}
57 BACKUP_INT32_1  {U8}{U8}
58 BACKUP_INT32_2  {INT16}{U8}
59 INT7_8UNSET     [\x00-\x7f]
60 INT7_8SET       [\x80-\xff]
61 VARINT          {INT7_8SET}{0,3}{INT7_8UNSET}
62 BACKUP_VARINT_0 {INT7_8SET}
63 BACKUP_VARINT_1 {INT7_8SET}{INT7_8SET}
64 BACKUP_VARINT_2 {INT7_8SET}{INT7_8SET}{INT7_8SET}
66 HEADER          MThd
67 TRACK           MTrk
68 BACKUP_TOP_0    MT
69 BACKUP_TOP_1    MTh
70 BACKUP_TOP_2    MTr
72 RUNNING_STATUS  [\x00-\x5f]
73 DATA_ENTRY      [\x60-\x79]
74 ALL_NOTES_OFF   [\x7a-\x7f]
75 NOTE_OFF        [\x80-\x8f]
76 NOTE_ON         [\x90-\x9f]
77 POLYPHONIC_AFTERTOUCH   [\xa0-\xaf]
78 CONTROLMODE_CHANGE      [\xb0-\xbf]
79 PROGRAM_CHANGE  [\xc0-\xcf]
80 CHANNEL_AFTERTOUCH      [\xd0-\xdf]
81 PITCHWHEEL_RANGE        [\xe0-\xef]
83 SYSEX_EVENT1    [\xf0]
84 SYSEX_EVENT2    [\xf7]
86 META_EVENT      [\xff]
88 SEQUENCE        [\x00][\x02]
89 YYTEXT          [\x01] 
90 YYCOPYRIGHT     [\x02]
91 YYTRACK_NAME    [\x03]
92 YYINSTRUMENT_NAME       [\x04]
93 YYLYRIC         [\x05]
94 YYMARKER                [\x06]
95 YYCUE_POINT     [\x07]
97 END_OF_TRACK    [\x2f][\x00]
98 TEMPO           [\x51][\x03]
99 SMPTE_OFFSET    [\x54][\x05]
100 TIME            [\x58][\x04]
101 KEY             [\x59][\x02]
102 SSME            [\0x7f][\x03]
106 {HEADER} {
107         LOGOUT(DEBUG_ver) << "lex: header" << endl;
108         yy_push_state(int16); 
109         yy_push_state(int16); 
110         yy_push_state(int16); 
111         yy_push_state(int32); 
112         return HEADER;
115 {TRACK} {
116         LOGOUT(DEBUG_ver) << "lex: track" << endl;
117         yy_push_state(track); 
118         yy_push_state(int32); 
119         return TRACK;
121 {U8}    {
122         error(String("top level: header expected: ")
123                 + String_convert::bin2hex_str(String(*YYText())));
124         exit(1);
126 {BACKUP_TOP_0} {
127         error(String("top level: header expected: ")
128                 + String_convert::bin2hex_str(String(*(YYText()))));
129         exit(1);
131 {BACKUP_TOP_1} {
132         error(String("top level: header expected: ")
133                 + String_convert::bin2hex_str(String(*(YYText()))));
134         exit(1);
136 {BACKUP_TOP_2} {
137         error(String("top level: header expected: ")
138                 + String_convert::bin2hex_str(String(*(YYText()))));
139         exit(1);
141 <int32>{INT32}  { // really signed? 
142         LOGOUT(DEBUG_ver) << "lex: int32" << endl;
143         assert(YYLeng() == 4);
144         String str((Byte const*)YYText(), YYLeng());
145         yylval.i = String_convert::bin2_i(str);
146         yy_pop_state();
147         return INT32;
149 <int32>{BACKUP_INT32_0} {
150         error(String("int32: int32 expected: ")
151                 + String_convert::bin2hex_str(String(*(YYText()))));
152         exit(1);
154 <int32>{BACKUP_INT32_1} {
155         error(String("int32: int32 expected: ")
156                 + String_convert::bin2hex_str(String(*(YYText()))));
157         exit(1);
159 <int32>{BACKUP_INT32_2} {
160         error(String("int32: int32 expected: ")
161                 + String_convert::bin2hex_str(String(*(YYText()))));
162         exit(1);
164 <int16>{INT16}  { // really signed?
165         LOGOUT(DEBUG_ver) << "lex: int16" << endl;
166         assert(YYLeng() == 2);
167         String str((Byte const*)YYText(), YYLeng());
168         yylval.i = (short)String_convert::bin2_i(str);
169         yy_pop_state();
170         return INT16;
172 <int16>{BACKUP_INT16_0} {
173         error(String("int16: int16 expected: ")
174                 + String_convert::bin2hex_str(String(*(YYText()))));
175         exit(1);
177 <i8>{I8}        {
178         LOGOUT(DEBUG_ver) << "lex: i8" << endl;
179         assert(YYLeng() == 1);
180 //      yylval.byte = *(signed char*)YYText();
181         yylval.i = *(signed char*)YYText();
182         yy_pop_state(); 
183         return I8;
185 <u8>{U8}        {
186         LOGOUT(DEBUG_ver) << "lex: u8" << endl;
187         assert(YYLeng() == 1);
188 //      yylval.byte = *(Byte*)YYText();
189         yylval.i = *(Byte*)YYText();
190         yy_pop_state(); 
191         return U8;
194 <track>{VARINT} {
195         String str((Byte const*)YYText(), YYLeng());
196         yylval.i = My_midi_lexer::varint2_i(str);
197         LOGOUT(DEBUG_ver) << String("lex: track: varint(") 
198                 + String(yylval.i) + "): "
199                 + String_convert::bin2hex_str(str) << endl;
200         yy_push_state(event); 
201         return VARINT;
203 <track>{U8}     {
204         error(String("track: illegal byte: ") 
205                 + String_convert::bin2hex_str(String(*YYText())));
206         exit(1);
208 <track>{BACKUP_VARINT_0}{U8} {
209         error(String("track: varint expected: ")
210                 + String_convert::bin2hex_str(String(*(YYText()))));
211         exit(1);
213 <track>{BACKUP_VARINT_1}{U8} {
214         error(String("track: varint expected: ")
215                 + String_convert::bin2hex_str(String(*(YYText()))));
216         exit(1);
218 <track>{BACKUP_VARINT_2}{U8} {
219         error(String("track: varint expected: ")
220                 + String_convert::bin2hex_str(String(*(YYText()))));
221         exit(1);
223 <event>{RUNNING_STATUS} {
224 //      yylval.byte = *(Byte*)YYText();
225 //      yylval.i = *(Byte*)YYText();
226         yylval.i = running_status_i_;
227         LOGOUT(DEBUG_ver) << String ("lex: running status: ") + String(yylval.i) << endl;
228         /*
229          'running status' rather means 'missing status'.
230          we'll put the running status data back, prepend (unput) 
231          the running status, and try again.
232          */
233         yyless(0);
234         unput(running_status_i_);
235         return RUNNING_STATUS;
237 <event>{DATA_ENTRY}     {
238 //      yylval.byte = *(Byte*)YYText();
239         yylval.i = *(Byte*)YYText();
240         LOGOUT(DEBUG_ver) << String ("lex: undefined data entry: ") + String(yylval.i) << endl;
241         yy_pop_state(); 
242         yy_push_state(u8);
243         return DATA_ENTRY;
245 <event>{ALL_NOTES_OFF}  {
246         LOGOUT(DEBUG_ver) << "lex: all note off" << endl;
247 //      yylval.byte = *(Byte*)YYText();
248         yylval.i = *(Byte*)YYText();
249         LOGOUT(DEBUG_ver) << String ("lex: all notes off: ") + String(yylval.i) << endl;
250         yy_pop_state(); 
251         yy_push_state(u8);
252         yy_push_state(u8);
253         return ALL_NOTES_OFF;
255 <event>{NOTE_OFF}       {
256         LOGOUT(DEBUG_ver) << "lex: note off" << endl;
257 //      yylval.byte = *(Byte*)YYText();
258         yylval.i = *(Byte*)YYText();
259         running_status_i_ = yylval.i;
260         yy_pop_state(); 
261         yy_push_state(u8);
262         yy_push_state(u8);
263         return NOTE_OFF;
265 <event>{NOTE_ON}        {
266         LOGOUT(DEBUG_ver) << "lex: note on" << endl;
267 //      yylval.byte = *(Byte*)YYText();
268         yylval.i = *(Byte*)YYText();
269         running_status_i_ = yylval.i;
270         yy_pop_state(); 
271         yy_push_state(u8);
272         yy_push_state(u8);
273         return NOTE_ON;
275 <event>{POLYPHONIC_AFTERTOUCH}  {
276         LOGOUT(DEBUG_ver) << "lex: polyphonic aftertouch" << endl;
277 //      yylval.byte = *(Byte*)YYText();
278         yylval.i = *(Byte*)YYText();
279         running_status_i_ = yylval.i;
280         yy_pop_state(); 
281         yy_push_state(u8);
282         yy_push_state(u8);
283         return POLYPHONIC_AFTERTOUCH;
285 <event>{CONTROLMODE_CHANGE}     {
286         LOGOUT(DEBUG_ver) << "lex: controlmode change" << endl;
287 //      yylval.byte = *(Byte*)YYText();
288         yylval.i = *(Byte*)YYText();
289         running_status_i_ = yylval.i;
290         yy_pop_state(); 
291         yy_push_state(u8);
292         yy_push_state(u8);
293         return CONTROLMODE_CHANGE;
295 <event>{PROGRAM_CHANGE} {
296         LOGOUT(DEBUG_ver) << "lex: program change" << endl;
297 //      yylval.byte = *(Byte*)YYText();
298         yylval.i = *(Byte*)YYText();
299         running_status_i_ = yylval.i;
300         yy_pop_state(); 
301         yy_push_state(u8);
302         return PROGRAM_CHANGE;
304 <event>{CHANNEL_AFTERTOUCH}     {
305         LOGOUT(DEBUG_ver) << "lex: channel aftertouch" << endl;
306 //      yylval.byte = *(Byte*)YYText();
307         yylval.i = *(Byte*)YYText();
308         running_status_i_ = yylval.i;
309         yy_pop_state(); 
310         yy_push_state(u8);
311         yy_push_state(u8);
312         return CHANNEL_AFTERTOUCH;
314 <event>{PITCHWHEEL_RANGE} {
315         LOGOUT(DEBUG_ver) << "lex: pitchwheel range" << endl;
316 //      yylval.byte = *(Byte*)YYText();
317         yylval.i = *(Byte*)YYText();
318         running_status_i_ = yylval.i;
319         yy_pop_state(); 
320         yy_push_state(u8);
321         yy_push_state(u8);
322         return PITCHWHEEL_RANGE;
324 <event>{SYSEX_EVENT1} { // len data
325         LOGOUT(DEBUG_ver) << "lex: sysex1" << endl;
326         yy_pop_state(); 
327         yy_push_state(data);
328         return SYSEX_EVENT1;
330 <event>{SYSEX_EVENT2} { // len data
331         LOGOUT(DEBUG_ver) << "lex: sysex2" << endl;
332         yy_pop_state(); 
333 //      yy_push_state(u8); //?
334         yy_push_state(data);
335         return SYSEX_EVENT2;
337 <event>{META_EVENT}     {
338         LOGOUT(DEBUG_ver) << "lex: meta" << endl;
339         yy_push_state(meta_event);
340         return META_EVENT;
342 <event>{U8}     {
343         error(String("event: illegal byte: ") 
344                 + String_convert::bin2hex_str(String(*YYText())));
345         exit(1);
347 <meta_event>{SEQUENCE}  {       // ssss sequence number
348         LOGOUT(DEBUG_ver) << "lex: sequence" << endl;
349         yy_pop_state();
350         yy_pop_state();
351         yy_push_state(int16);
352         return SEQUENCE;
354 <meta_event>{YYTEXT}    {               // len data
355         LOGOUT(DEBUG_ver) << "lex: text" << endl;
356 //      yylval.byte = *(Byte*)YYText();
357         yylval.i = *(Byte*)YYText();
358         yy_pop_state();
359         yy_pop_state();
360         yy_push_state(data);
361         return YYTEXT;
363 <meta_event>{YYCOPYRIGHT}       {
364         LOGOUT(DEBUG_ver) << "lex: copyright" << endl;
365 //      yylval.byte = *(Byte*)YYText();
366         yylval.i = *(Byte*)YYText();
367         yy_pop_state();
368         yy_pop_state();
369         yy_push_state(data);
370         return YYCOPYRIGHT;
372 <meta_event>{YYTRACK_NAME}      {
373         LOGOUT(DEBUG_ver) << "lex: track name" << endl;
374 //      yylval.byte = *(Byte*)YYText();
375         yylval.i = *(Byte*)YYText();
376         yy_pop_state();
377         yy_pop_state();
378         yy_push_state(data);
379         return YYTRACK_NAME;
381 <meta_event>{YYINSTRUMENT_NAME} {
382         LOGOUT(DEBUG_ver) << "lex: instrument name" << endl;
383 //      yylval.byte = *(Byte*)YYText();
384         yylval.i = *(Byte*)YYText();
385         yy_pop_state();
386         yy_pop_state();
387         yy_push_state(data);
388         return YYINSTRUMENT_NAME;
390 <meta_event>{YYLYRIC}   {
391         LOGOUT(DEBUG_ver) << "lex: lyric" << endl;
392 //      yylval.byte = *(Byte*)YYText();
393         yylval.i = *(Byte*)YYText();
394         yy_pop_state();
395         yy_pop_state();
396         yy_push_state(data);
397         return YYLYRIC;
399 <meta_event>{YYMARKER}  {
400         LOGOUT(DEBUG_ver) << "lex: marker" << endl;
401 //      yylval.byte = *(Byte*)YYText();
402         yylval.i = *(Byte*)YYText();
403         yy_pop_state();
404         yy_pop_state();
405         yy_push_state(data);
406         return YYMARKER;
408 <meta_event>{YYCUE_POINT}       {
409         LOGOUT(DEBUG_ver) << "lex: cue point" << endl;
410 //      yylval.byte = *(Byte*)YYText();
411         yylval.i = *(Byte*)YYText();
412         yy_pop_state();
413         yy_pop_state();
414         yy_push_state(data);
415         return YYCUE_POINT;
417 <meta_event>{TEMPO}     {       // tttttt usec
418         LOGOUT(DEBUG_ver) << "lex: tempo" << endl;
419         yy_pop_state();
420         yy_pop_state();
421         yy_push_state(u8);
422         yy_push_state(u8);
423         yy_push_state(u8);
424         return TEMPO;
426 <meta_event>{SMPTE_OFFSET}      {               // hr mn se fr ff
427         LOGOUT(DEBUG_ver) << "lex: smpte offset" << endl;
428         yy_pop_state();
429         yy_pop_state();
430         yy_push_state(u8);
431         yy_push_state(u8);
432         yy_push_state(u8);
433         yy_push_state(u8);
434         yy_push_state(u8);
435         return SMPTE_OFFSET;
437 <meta_event>{TIME}      {               // nn dd cc bb
438         LOGOUT(DEBUG_ver) << "lex: time" << endl;
439         yy_pop_state();
440         yy_pop_state();
441         yy_push_state(u8);
442         yy_push_state(u8);
443         yy_push_state(u8);
444         yy_push_state(u8);
445         return TIME;
447 <meta_event>{KEY}       {       // sf mi
448         LOGOUT(DEBUG_ver) << "lex: key" << endl;
449         yy_pop_state();
450         yy_pop_state();
451         yy_push_state(i8);
452         yy_push_state(i8);
453         return KEY;
455 <meta_event>{SSME}      {       // len data
456         LOGOUT(DEBUG_ver) << "lex: smme" << endl;
457         yy_pop_state();
458         yy_pop_state();
459         yy_push_state(data);
460         return SSME;
462 <meta_event>{END_OF_TRACK} {
463         LOGOUT(DEBUG_ver) << "lex: end of track" << endl;
464         yy_pop_state();
465         yy_pop_state();
466         yy_pop_state();
467         return END_OF_TRACK;
469 <meta_event>{U8} {
470         warning(String("meta_event: unimplemented event: ")
471                 + String_convert::bin2hex_str(String(*YYText()))
472 // huh?
473 //              ,this->here_ch_C() 
474         );
475         yy_pop_state();
476         yy_pop_state();
477         yy_push_state(u8); 
478         yy_push_state(u8);
479         return U8;
482 <data>{VARINT} {
483         LOGOUT(DEBUG_ver) << "lex: data" << endl;
484         String str((Byte const*)YYText(), YYLeng());
485         int i = My_midi_lexer::varint2_i(str);
486         String* str_p = new String;
487         while (i--)
488                 *str_p += (char)yyinput();
489         yylval.str_p = str_p;
490         yy_pop_state();
491         return DATA;
493 <data>{U8}      {
494         error(String("data: illegal byte: ")
495                 + String_convert::bin2hex_str(String(*YYText())));
496         exit(1);
498 <data>{BACKUP_VARINT_0}{U8} {
499         error(String("data: varint expected: ")
500                 + String_convert::bin2hex_str(String(*(YYText()))));
501         exit(1);
503 <data>{BACKUP_VARINT_1}{U8} {
504         error(String("data: varint expected: ")
505                 + String_convert::bin2hex_str(String(*(YYText()))));
506         exit(1);
508 <data>{BACKUP_VARINT_2}{U8} {
509         error(String("data: varint expected: ")
510                 + String_convert::bin2hex_str(String(*(YYText()))));
511         exit(1);
514 <<EOF>> {
515 //      LOGOUT(NORMAL_ver) << "<<EOF>>";
517         if (!close_i())
518           yyterminate(); // can't move this, since it actually rets a YY_NULL