Dependencies:   mbed

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