Bernard Escaillas
/
MidiTee
parse.h
- Committer:
- Midimetric
- Date:
- 2011-06-07
- Revision:
- 0:71d791204057
File content as of revision 0:71d791204057:
#ifndef PARSE_H #define PARSE_H #include <string.h> #include <vector> void ParseCleanUp( char* s1, char* s2 ) { // copy all non blank till ; or 0 for( int i = 0, j = 0 ; i < 256 ; i++ ) if( s1[i] != 32 && s1[i] != 13 && s1[i] != 10 && s1[i] != 9 ) switch( s2[j++] = s1[i] ) { case ';': s2[j-1] = 0; return; case 0: return; } } int GetOPIDfromFunction( char * f ) { if( strcmp( f, "add" ) == 0 ) return ADD; if( strcmp( f, "mul" ) == 0 ) return MUL; if( strcmp( f, "sub" ) == 0 ) return SUB; if( strcmp( f, "div" ) == 0 ) return DIV; if( strcmp( f, "i8" ) == 0 ) return E8_; if( strcmp( f, "i14" ) == 0 ) return E14; if( strcmp( f, "mod" ) == 0 ) return MOD; if( strcmp( f, "bit" ) == 0 ) return BIT; if( strcmp( f, "bor" ) == 0 ) return BOR; if( strcmp( f, "ban" ) == 0 ) return BAN; if( strcmp( f, "bno" ) == 0 ) return BNO; if( strcmp( f, "bsl" ) == 0 ) return BSL; if( strcmp( f, "bsr" ) == 0 ) return BSR; if( strcmp( f, "msb" ) == 0 ) return MSB; if( strcmp( f, "lsb" ) == 0 ) return LSB; if( strcmp( f, "map" ) == 0 ) return MAP; if( strcmp( f, "nrpn") == 0 ) return NPN; if( strcmp( f, "rpn" ) == 0 ) return RPN; if( strcmp( f, "bank") == 0 ) return BNK; if( strcmp( f, "nrp8") == 0 ) return NP8; return 0; } int ParseError = 0; int ParseLine = 0; #define abort(x) { ParseError = x; return false; } #define PARSE_NOERROR 0 #define PARSE_NO_FILE 1 #define PARSE_BAD_NUMBER_DEFINITION 2 #define PARSE_BAD_MESSAGE_DEFINITION 3 #define PARSE_BAD_SEQ_SYNTAXE 4 #define PARSE_BAD_SEQ_HEXA_SIGN 5 #define PARSE_BAD_SEQ_NUMBER 6 #define PARSE_BAD_SEQ_IDENTIFIER 7 #define PARSE_BAD_SEQ_BYTE 8 #define PARSE_BAD_SEQ_FUNCTION 9 #define PARSE_BAD_SEQ_TOOLONG 10 #define PARSE_UNKNWON_ENTRY 11 #define PARSE_MIN_GREATER_THAN_MAX 12 #define TOKEN_END *p == 0 || *p == ',' || *p == ')' #define TOKEN_NUM *p >= '0' && *p <= '9' #define TOKEN_LOW *p >= 'a' && *p <= 'z' #define TOKEN_UPP *p >= 'A' && *p <= 'Z' #define TOKEN_LOX *p >= 'a' && *p <= 'f' #define TOKEN_UPX *p >= 'A' && *p <= 'F' class ParseEntry { public: char Name[17]; ParseEntry( char* name ) { short i = 0; for( i = 0 ; i < 16 && name[i] ; i++ ) { if( name[i] >= 'A' && name[i]<='Z' ) Name[i] = name[i] + 32; else Name[i] = name[i]; } Name[i] = 0; } virtual ~ParseEntry() {} virtual bool Parse( char* data ){ return true; } }; class ParseFlag : public ParseEntry { public: int Flag; ParseFlag( char* name ) : ParseEntry( name ), Flag(0) {} virtual ~ParseFlag(){} virtual bool Parse( char* data ) { if( *data == '*' ) { Flag = NAKW; return true; } Flag = 0; for( int i = 0 ; i < 16 ; i++ ) if( data[i] == 0 ) break; else if( data[i] != '-' ) Flag |= 1 << i; return true; } }; class ParseByte : public ParseEntry { public: byte Mini; byte Maxi; ParseByte( char* name ) : ParseEntry( name ),Mini(NAKN), Maxi(NAKN) {} virtual ~ParseByte(){} virtual bool Parse( char* data ) { if( *data == '*' ) { Mini = NAKN; Maxi = NAKN; return true; } int base = 10; bool start = true; int dot = 0; char set[] = "0123456789ABCDEF$."; char* p; bool ok = false; Mini = 0; while( *data ) { ok = false; p = strchr( set, *data++ ); if( p ) { int index = p - set; if( index==16 && start==true ) { start=false; base=16, ok=true; } else if( index == 17 && dot < 3 ) { dot++; if( dot==3) { start=true; base=10; Maxi = 0; ok=true; } } else if( index < base ) { if( dot==3 ) { start=false; Maxi = Maxi * base + index; ok=true; } else { start=false; Mini = Mini * base + index; ok=true; } } else break; } else break; } if( ! ok ) abort( PARSE_BAD_NUMBER_DEFINITION ) if( Maxi != NAKN && Mini > Maxi ) abort( PARSE_MIN_GREATER_THAN_MAX ) return true; } }; class ParseShort : public ParseEntry { public: short Mini; short Maxi; ParseShort( char* name ) : ParseEntry( name ),Mini(NAKW), Maxi(NAKW) {} virtual ~ParseShort(){} virtual bool Parse( char* data ) { if( *data == '*' ) { Mini = NAKW; Maxi = NAKW; return true; } int base = 10; bool start = true; int dot = 0; char set[] = "0123456789ABCDEF$."; char* p; bool ok = false; Mini = 0; while( *data ) { ok = false; p = strchr( set, *data++ ); if( p ) { int index = p - set; if( index==16 && start==true ) { start=false; base=16, ok=true; } else if( index == 17 && dot < 3 ) { dot++; if( dot==3) { start=true; base=10; Maxi = 0; ok=true; } } else if( index < base ) { if( dot==3 ) { start=false; Maxi = Maxi * base + index; ok=true; } else { start=false; Mini = Mini * base + index; ok=true; } } else break; } else break; } if( ! ok ) abort( PARSE_BAD_NUMBER_DEFINITION ) if( Maxi != NAKW && Mini>Maxi ) abort( PARSE_MIN_GREATER_THAN_MAX ) return true; } }; class ParseMessage : public ParseEntry { public: byte Code; ParseMessage( char* name ) : ParseEntry( name ),Code(NAKN) {} virtual ~ParseMessage(){} virtual bool Parse( char* data ) { static char keywords[] = "NOTE;POLA;CTRL;PROG;BANK;DATA;INCR;DECR;RPN_;NRPN;MONA;BEND;SYSX;TCOD;SPOS;SSEL;TUNE;CLOK;STAR;CONT;STOP;SENS;RSET"; char* p = strstr( keywords, data ); if( p == NULL ) abort( PARSE_BAD_MESSAGE_DEFINITION ) Code = ( p - keywords ) / 5 + 1; return true; } }; #define PUSH(x) Sequence.push_back(x) class ParseSequence : public ParseEntry { public: vector<short> Sequence; ParseSequence( char* name ) : ParseEntry(name) {} virtual ~ParseSequence() { } virtual bool Parse( char* data ) { if( *data == '*' ) { Sequence = vector<short>( 1, RAW ); return true; } char* p = data; if( SubParse( p ) ) { Sequence.push_back(NOP); return true; } return false; } short SubParse( char* &p ) // returns the number of arguments in the sub-sequence { static int level = 0; level++; int args = 0; while( *p ) { int num = 0; switch( *p ) { case '=': case ',': p++; break; case ')': p++; level--; return args; case '$': while( 1 ) { p++; if( TOKEN_END ) { PUSH( num ); break; } else if( TOKEN_NUM ) num = num * 16 + (*p - 48 ); else if( TOKEN_UPX ) num = num * 16 + (*p - 55 ); else if( TOKEN_LOX ) num = num * 16 + (*p - 87 ); else abort( PARSE_BAD_SEQ_HEXA_SIGN ) } args++; break; case '%': { char fn[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int i = 0; while( 1 ) { p++; if( TOKEN_END ) break; else if( TOKEN_NUM ) fn[i++] = *p; else if( TOKEN_UPP ) fn[i++] = *p + 32; else if( TOKEN_LOW ) fn[i++] = *p; else abort( PARSE_BAD_SEQ_IDENTIFIER ) if( i == 16 ) abort( PARSE_BAD_SEQ_TOOLONG ) } if( strcmp( fn, "mc") == 0 ) PUSH( VMC ); else if( strcmp( fn, "m" ) == 0 ) PUSH( VM_ ); else if( strcmp( fn, "c" ) == 0 ) PUSH( VC_ ); else if( strcmp( fn, "a" ) == 0 ) PUSH( VA_ ); else if( strcmp( fn, "b" ) == 0 ) PUSH( VB_ ); else if( strcmp( fn, "n" ) == 0 ) PUSH( VN_ ); else if( strcmp( fn, "d" ) == 0 ) PUSH( VD_ ); else if( strcmp( fn, "k" ) == 0 ) PUSH( VK_ ); else { for( int j = 0 ; j < i ; j++ ) PUSH( CID + fn[j] ); PUSH( CID ); } } args++; break; default: if( TOKEN_UPP ) *p += 32; if( TOKEN_LOW ) { char fn[] = {*p,0,0,0,0,0,0,0,0,0}; int i = 1; while( 1 ) { p++; if( *p == '(' ) break; else if( TOKEN_UPP ) fn[i++] = *p + 32; else if( TOKEN_LOW ) fn[i++] = *p; else if( TOKEN_NUM ) fn[i++] = *p; else abort(PARSE_BAD_SEQ_FUNCTION) } p++; // skip ( if( level == 1 ) PUSH( SEQ ); short a = SubParse( p ); if( a == 0 ) return 0; int n = GetOPIDfromFunction( fn ); if( n == 0 ) abort(PARSE_BAD_SEQ_FUNCTION) if( n == MAP ) PUSH( a ); PUSH( n ); if( level==1 && n!=E8_ && n!=E14 && n!=RPN && n!=NPN && n!=BNK && n!=NP8 ) PUSH( E7_ ); args++; break; } if( TOKEN_NUM ) { num = *p - 48; while( 1 ) { p++; if( TOKEN_END ) { PUSH( num ); break; } else if( TOKEN_NUM ) num = num * 10 + (*p - 48 ); else abort( PARSE_BAD_SEQ_NUMBER ) } args++; break; } abort( PARSE_BAD_SEQ_SYNTAXE ) } } level--; return args; } }; class ParseRoute { public : byte Inport; byte Message; short Channels; short minA; short maxA; short minB; short maxB; vector<byte> Head; vector<short> Sequence1; vector<short> Sequence2; vector<short> Sequence3; vector<Assignment*> Assigns; ParseRoute() : Inport(0), Message(NAKN), Channels(NAKW), minA(NAKN), maxA(NAKN), minB(NAKN), maxB(NAKN) {} ~ParseRoute() { } bool Add( ParseEntry* entry ) { ParseMessage* m = (ParseMessage*)entry; ParseFlag* f = (ParseFlag*)entry; ParseByte* b = (ParseByte*)entry; ParseShort* s = (ParseShort*)entry; ParseSequence* q = (ParseSequence*)entry; if( strcmp( entry->Name, "input1" ) == 0 ) { Inport = 0; Message = m->Code; return true; } else if( strcmp( entry->Name, "input2" ) == 0 ) { Inport = 1; Message = m->Code; return true; } else if( strcmp( entry->Name, "input3" ) == 0 ) { Inport = 2; Message = m->Code; return true; } else if( strcmp( entry->Name, "channels" ) == 0 ) { Channels = f->Flag; return true; } else if( strcmp( entry->Name, "program" ) == 0 ) { minA = b->Mini; maxA = b->Maxi; return true; } else if( strcmp( entry->Name, "valuea" ) == 0 ) { minA = b->Mini; maxA = b->Maxi; return true; } else if( strcmp( entry->Name, "valueb" ) == 0 ) { minB = b->Mini; maxB = b->Maxi; return true; } else if( strcmp( entry->Name, "parameter") == 0 ) { minA = s->Mini; maxA = s->Maxi; return true; } else if( strcmp( entry->Name, "data" ) == 0 ) { minB = s->Mini; maxB = s->Maxi; return true; } else if( strcmp( entry->Name, "bank" ) == 0 ) { minA = s->Mini; maxA = s->Maxi; return true; } else if( strcmp( entry->Name, "output1" ) == 0 ) { Sequence1.insert( Sequence1.end(), q->Sequence.begin(), q->Sequence.end() ); return true; } else if( strcmp( entry->Name, "output2" ) == 0 ) { Sequence2.insert( Sequence2.end(), q->Sequence.begin(), q->Sequence.end() ); return true; } else if( strcmp( entry->Name, "output3" ) == 0 ) { Sequence3.insert( Sequence3.end(), q->Sequence.begin(), q->Sequence.end() ); return true; } else if( strcmp( entry->Name, "header" ) == 0 ) { Head.insert( Head.end(), q->Sequence.begin(), q->Sequence.end() ); return true; } else if( entry->Name[0] == '%' ) { Assigns.push_back( new Assignment( entry->Name + 1 /* skip the %*/, q->Sequence ) ); return true; } ParseError = PARSE_UNKNWON_ENTRY; return false; } bool Done() { FL.Add( Inport, Message, Channels, minA, maxA, minB, maxB, Head, Sequence1, Sequence2, Sequence3, Assigns ); return true; } }; const char keywords_flag[] = "channels"; const char keywords_nums[] = "valueA valueB program"; const char keywords_nu14[] = "parameter data bank"; const char keywords_mess[] = "input1 input2 input3"; const char keywords_sequ[] = "output1 output2 output3 header"; bool Parse() { char Line1[256]; char Line2[256]; LocalFileSystem local("local"); FILE* f = fopen( "/local/filter.txt", "r" ); if( f == NULL ) { ParseError = PARSE_NO_FILE; return false; } ParseRoute* pr = NULL; ParseLine = 0; while( /* ( ParseLine < 200 ) && */ fgets( Line1, 256, f ) ) { ParseLine++; ParseEntry* sp = NULL; ParseCleanUp( Line1, Line2 ); strtok( Line2, ":" ); if( Line2[0] == 0 || Line2[0] == 10 ) continue; if( strcmp( Line2, "ROUTE" ) == 0 ) { if( pr ) if( ! pr->Done() ) goto Bad; delete pr; pr = NULL; int mem = AvailableMemory(); if( mem < 512 ) { printf("Only %d bytes left for program.\nFilter definitions reading stopped at line %d\n", mem, ParseLine ); break; } pr = new ParseRoute(); } else if( strstr( keywords_flag, Line2 ) ) sp = new ParseFlag( Line2 ); else if( strstr( keywords_nums, Line2 ) ) sp = new ParseByte( Line2 ); else if( strstr( keywords_nu14, Line2 ) ) sp = new ParseShort( Line2 ); else if( strstr( keywords_mess, Line2 ) ) sp = new ParseMessage( Line2 ); else if( strstr( keywords_sequ, Line2 ) ) sp = new ParseSequence(Line2 ); else if( Line2[0] == '%' ) sp = new ParseSequence(Line2 ); else { ParseError = PARSE_UNKNWON_ENTRY; goto Bad; } if( sp != NULL ) { if( pr == NULL ) goto Bad; if( ! sp->Parse( strtok( NULL, "\n" ) ) ) goto Bad; if( ! pr->Add( sp ) ) goto Bad; delete sp; } } if( pr ) if( ! pr->Done() ) goto Bad; fclose( f ); return true; Bad: if( f != NULL ) fclose(f); return false; } #undef abort #undef TOKEN_END #undef TOKEN_NUM #undef TOKEN_LOW #undef TOKEN_UPP #undef TOKEN_LOX #undef TOKEN_UPX #endif