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
16 after making a change to the lexer rules, run
17 flex -b <this lexer file>
20 contains no backup states, but only the reminder
21 Compressed tables always back up.
22 (don-t forget to rm lex.yy.cc :-)
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
39 %option yyclass="My_midi_lexer"
57 BACKUP_INT32_1 {U8}{U8}
58 BACKUP_INT32_2 {INT16}{U8}
59 INT7_8UNSET [\x00-\x7f]
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}
72 RUNNING_STATUS [\x00-\x5f]
73 DATA_ENTRY [\x60-\x79]
74 ALL_NOTES_OFF [\x7a-\x7f]
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]
92 YYINSTRUMENT_NAME [\x04]
97 END_OF_TRACK [\x2f][\x00]
99 SMPTE_OFFSET [\x54][\x05]
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);
116 LOGOUT(DEBUG_ver) << "lex: track" << endl;
117 yy_push_state(track);
118 yy_push_state(int32);
122 error(String("top level: header expected: ")
123 + String_convert::bin2hex_str(String(*YYText())));
127 error(String("top level: header expected: ")
128 + String_convert::bin2hex_str(String(*(YYText()))));
132 error(String("top level: header expected: ")
133 + String_convert::bin2hex_str(String(*(YYText()))));
137 error(String("top level: header expected: ")
138 + String_convert::bin2hex_str(String(*(YYText()))));
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);
149 <int32>{BACKUP_INT32_0} {
150 error(String("int32: int32 expected: ")
151 + String_convert::bin2hex_str(String(*(YYText()))));
154 <int32>{BACKUP_INT32_1} {
155 error(String("int32: int32 expected: ")
156 + String_convert::bin2hex_str(String(*(YYText()))));
159 <int32>{BACKUP_INT32_2} {
160 error(String("int32: int32 expected: ")
161 + String_convert::bin2hex_str(String(*(YYText()))));
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);
172 <int16>{BACKUP_INT16_0} {
173 error(String("int16: int16 expected: ")
174 + String_convert::bin2hex_str(String(*(YYText()))));
178 LOGOUT(DEBUG_ver) << "lex: i8" << endl;
179 assert(YYLeng() == 1);
180 // yylval.byte = *(signed char*)YYText();
181 yylval.i = *(signed char*)YYText();
186 LOGOUT(DEBUG_ver) << "lex: u8" << endl;
187 assert(YYLeng() == 1);
188 // yylval.byte = *(Byte*)YYText();
189 yylval.i = *(Byte*)YYText();
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);
204 error(String("track: illegal byte: ")
205 + String_convert::bin2hex_str(String(*YYText())));
208 <track>{BACKUP_VARINT_0}{U8} {
209 error(String("track: varint expected: ")
210 + String_convert::bin2hex_str(String(*(YYText()))));
213 <track>{BACKUP_VARINT_1}{U8} {
214 error(String("track: varint expected: ")
215 + String_convert::bin2hex_str(String(*(YYText()))));
218 <track>{BACKUP_VARINT_2}{U8} {
219 error(String("track: varint expected: ")
220 + String_convert::bin2hex_str(String(*(YYText()))));
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;
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.
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;
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;
253 return ALL_NOTES_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;
266 LOGOUT(DEBUG_ver) << "lex: note on" << endl;
267 // yylval.byte = *(Byte*)YYText();
268 yylval.i = *(Byte*)YYText();
269 running_status_i_ = yylval.i;
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;
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;
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;
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;
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;
322 return PITCHWHEEL_RANGE;
324 <event>{SYSEX_EVENT1} { // len data
325 LOGOUT(DEBUG_ver) << "lex: sysex1" << endl;
330 <event>{SYSEX_EVENT2} { // len data
331 LOGOUT(DEBUG_ver) << "lex: sysex2" << endl;
333 // yy_push_state(u8); //?
337 <event>{META_EVENT} {
338 LOGOUT(DEBUG_ver) << "lex: meta" << endl;
339 yy_push_state(meta_event);
343 error(String("event: illegal byte: ")
344 + String_convert::bin2hex_str(String(*YYText())));
347 <meta_event>{SEQUENCE} { // ssss sequence number
348 LOGOUT(DEBUG_ver) << "lex: sequence" << endl;
351 yy_push_state(int16);
354 <meta_event>{YYTEXT} { // len data
355 LOGOUT(DEBUG_ver) << "lex: text" << endl;
356 // yylval.byte = *(Byte*)YYText();
357 yylval.i = *(Byte*)YYText();
363 <meta_event>{YYCOPYRIGHT} {
364 LOGOUT(DEBUG_ver) << "lex: copyright" << endl;
365 // yylval.byte = *(Byte*)YYText();
366 yylval.i = *(Byte*)YYText();
372 <meta_event>{YYTRACK_NAME} {
373 LOGOUT(DEBUG_ver) << "lex: track name" << endl;
374 // yylval.byte = *(Byte*)YYText();
375 yylval.i = *(Byte*)YYText();
381 <meta_event>{YYINSTRUMENT_NAME} {
382 LOGOUT(DEBUG_ver) << "lex: instrument name" << endl;
383 // yylval.byte = *(Byte*)YYText();
384 yylval.i = *(Byte*)YYText();
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();
399 <meta_event>{YYMARKER} {
400 LOGOUT(DEBUG_ver) << "lex: marker" << endl;
401 // yylval.byte = *(Byte*)YYText();
402 yylval.i = *(Byte*)YYText();
408 <meta_event>{YYCUE_POINT} {
409 LOGOUT(DEBUG_ver) << "lex: cue point" << endl;
410 // yylval.byte = *(Byte*)YYText();
411 yylval.i = *(Byte*)YYText();
417 <meta_event>{TEMPO} { // tttttt usec
418 LOGOUT(DEBUG_ver) << "lex: tempo" << endl;
426 <meta_event>{SMPTE_OFFSET} { // hr mn se fr ff
427 LOGOUT(DEBUG_ver) << "lex: smpte offset" << endl;
437 <meta_event>{TIME} { // nn dd cc bb
438 LOGOUT(DEBUG_ver) << "lex: time" << endl;
447 <meta_event>{KEY} { // sf mi
448 LOGOUT(DEBUG_ver) << "lex: key" << endl;
455 <meta_event>{SSME} { // len data
456 LOGOUT(DEBUG_ver) << "lex: smme" << endl;
462 <meta_event>{END_OF_TRACK} {
463 LOGOUT(DEBUG_ver) << "lex: end of track" << endl;
470 warning(String("meta_event: unimplemented event: ")
471 + String_convert::bin2hex_str(String(*YYText()))
473 // ,this->here_ch_C()
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;
488 *str_p += (char)yyinput();
489 yylval.str_p = str_p;
494 error(String("data: illegal byte: ")
495 + String_convert::bin2hex_str(String(*YYText())));
498 <data>{BACKUP_VARINT_0}{U8} {
499 error(String("data: varint expected: ")
500 + String_convert::bin2hex_str(String(*(YYText()))));
503 <data>{BACKUP_VARINT_1}{U8} {
504 error(String("data: varint expected: ")
505 + String_convert::bin2hex_str(String(*(YYText()))));
508 <data>{BACKUP_VARINT_2}{U8} {
509 error(String("data: varint expected: ")
510 + String_convert::bin2hex_str(String(*(YYText()))));
515 // LOGOUT(NORMAL_ver) << "<<EOF>>";
518 yyterminate(); // can't move this, since it actually rets a YY_NULL