Diff: parse.h
- Revision:
- 0:71d791204057
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/parse.h Tue Jun 07 13:32:20 2011 +0000
@@ -0,0 +1,448 @@
+#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
\ No newline at end of file