/**CFile****************************************************************

  FileName    [wlcReadSmt.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Verilog parser.]

  Synopsis    [Parses several flavors of word-level Verilog.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - August 22, 2014.]

  Revision    [$Id: wlcReadSmt.c,v 1.00 2014/09/12 00:00:00 alanmi Exp $]

***********************************************************************/

#include "wlc.h"

ABC_NAMESPACE_IMPL_START

////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

// parser name types
typedef enum { 
    PRS_SMT_NONE = 0, 
    PRS_SMT_INPUT,    
    PRS_SMT_CONST,    
    PRS_SMT_LET,   
    PRS_SMT_ASSERT,
    PRS_SMT_VALUE
} Prs_ManType_t; 

// parser
typedef struct Prs_Smt_t_ Prs_Smt_t;
struct Prs_Smt_t_
{
    // input data
    char *       pName;       // file name
    char *       pBuffer;     // file contents
    char *       pLimit;      // end of file
    char *       pCur;        // current position
    Abc_Nam_t *  pStrs;       // string manager
    // network structure
    Vec_Int_t    vData;
    Vec_Int_t    vValues;
    // error handling
    char ErrorStr[1000];      
};


// create error message
static inline int Prs_SmtErrorSet( Prs_Smt_t * p, char * pError, int Value )
{
    assert( !p->ErrorStr[0] );
    sprintf( p->ErrorStr, "%s", pError );
    return Value;
}
// clear error message
static inline void Prs_SmtErrorClear( Prs_Smt_t * p )
{
    p->ErrorStr[0] = '\0';
}
// print error message
static inline int Prs_SmtErrorPrint( Prs_Smt_t * p )
{
    char * pThis; int iLine = 0;
    if ( !p->ErrorStr[0] ) return 1;
    for ( pThis = p->pBuffer; pThis < p->pCur; pThis++ )
        iLine += (int)(*pThis == '\n');
    printf( "Line %d: %s\n", iLine, p->ErrorStr );
    return 0;
}
static inline char * Prs_SmtLoadFile( char * pFileName, char ** ppLimit )
{
    char * pBuffer;
    int nFileSize, RetValue;
    FILE * pFile = fopen( pFileName, "rb" );
    if ( pFile == NULL )
    {
        printf( "Cannot open input file.\n" );
        return NULL;
    }
    // get the file size, in bytes
    fseek( pFile, 0, SEEK_END );  
    nFileSize = ftell( pFile );  
    // move the file current reading position to the beginning
    rewind( pFile ); 
    // load the contents of the file into memory
    pBuffer = ABC_ALLOC( char, nFileSize + 3 );
    pBuffer[0] = '\n';
    RetValue = fread( pBuffer+1, nFileSize, 1, pFile );
    // terminate the string with '\0'
    pBuffer[nFileSize + 0] = '\n';
    pBuffer[nFileSize + 1] = '\0';
    *ppLimit = pBuffer + nFileSize + 2;
    return pBuffer;
}
static inline Prs_Smt_t * Prs_SmtAlloc( char * pFileName, char * pBuffer, char * pLimit )
{
    Prs_Smt_t * p;
    p = ABC_CALLOC( Prs_Smt_t, 1 );
    p->pName   = pFileName;
    p->pBuffer = pBuffer;
    p->pLimit  = pLimit;
    p->pCur    = pBuffer;
    p->pStrs   = Abc_NamStart( 1000, 24 );
    Vec_IntGrow ( &p->vData, 1000 );
    return p;
}

static inline void Prs_SmtFree( Prs_Smt_t * p )
{
    if ( p->pStrs )
        Abc_NamDeref( p->pStrs );
    Vec_IntErase( &p->vData );
    Vec_IntErase( &p->vValues );
    ABC_FREE( p );
}

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Prs_SmtRemoveComments( Prs_Smt_t * p )
{
    char * pTemp;
    for ( pTemp = p->pBuffer; pTemp < p->pLimit; pTemp++ )
        if ( *pTemp == ';' )
            while ( *pTemp && *pTemp != '\n' )
                *pTemp++ = ' ';
}
static inline void Prs_SmtSkipSpaces( Prs_Smt_t * p )
{
    while ( *p->pCur == ' ' || *p->pCur == '\t' || *p->pCur == '\r' || *p->pCur == '\n' )
        p->pCur++;
}
static inline int Prs_SmtIsWord( Prs_Smt_t * p, char * pWord )
{
    Prs_SmtSkipSpaces( p );
    if ( strncmp( p->pCur, pWord, strlen(pWord) ) )
        return 0;
    p->pCur += strlen(pWord);
    Prs_SmtSkipSpaces( p );
    return 1;
}
static inline char * Prs_SmtFindNextPar( Prs_Smt_t * p )
{
    char * pTemp; int Count = 1;
    for ( pTemp = p->pCur; pTemp < p->pLimit; pTemp++ )
    {
        if ( *pTemp == '(' )
            Count++;
        else if ( *pTemp == ')' )
            Count--;
        if ( Count == 0 )
            break;
    }
    assert( *pTemp == ')' );
    return pTemp;
}
static inline int Prs_SmtParseLet( Prs_Smt_t * p, char * pLimit, int Type )
{
    char * pToken;
    assert( *pLimit == ')' );
    *pLimit = 0;
    Vec_IntPush( &p->vData, 0 );
    Vec_IntPush( &p->vData, Type );
    pToken = strtok( p->pCur, " ()" );
    while ( pToken )
    {
        if ( pToken[0] != '_' && pToken[0] != '=' )
            Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, pToken, NULL) );
        pToken = strtok( NULL, " ()" );
    }
    assert( *pLimit == 0 );
    *pLimit = ')';
    p->pCur = pLimit;
    return 1;
}
static inline int Prs_SmtParseFun( Prs_Smt_t * p, char * pLimit, int Type )
{
    char * pToken;
    assert( *pLimit == ')' );
    *pLimit = 0;
    Vec_IntPush( &p->vData, 0 );
    Vec_IntPush( &p->vData, Type );
    pToken = strtok( p->pCur, " ()" );
    assert( pToken != NULL );
    Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, pToken, NULL) );
    pToken = strtok( NULL, " ()" );
    if ( pToken[0] == '_' )
        pToken = strtok( NULL, " ()" );
    if ( !strcmp(pToken, "Bool") )
    {
        Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, "1", NULL) );
        pToken = strtok( NULL, " ()" );
        if ( !strcmp(pToken, "false") )
            Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, "#b0", NULL) );
        else if ( !strcmp(pToken, "true") )
            Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, "#b1", NULL) );
        else assert( 0 );
    }
    else if ( !strcmp(pToken, "BitVec") )
    {
        pToken = strtok( NULL, " ()" );
        Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, pToken, NULL) );
        pToken = strtok( NULL, " ()" );
        if ( pToken )
        {
            Vec_IntPush( &p->vData, Abc_NamStrFindOrAdd(p->pStrs, pToken, NULL) );
            pToken = strtok( NULL, " ()" );
            if ( pToken != NULL )
                return Prs_SmtErrorSet(p, "Trailing symbols are not recognized.", 0);
        }
    }
    else 
        return Prs_SmtErrorSet(p, "Expecting either \"Bool\" or \"BitVec\".", 0);
    assert( *pLimit == 0 );
    *pLimit = ')';
    p->pCur = pLimit;
    return 1;
}
static inline int Prs_SmtParseValue( Prs_Smt_t * p, char * pLimit, int Type )
{
    char * pToken;
    assert( *pLimit == ')' );
    *pLimit = 0;
    pToken = strtok( p->pCur, " ()" );
    assert( pToken != NULL );
    Vec_IntPush( &p->vValues, Abc_NamStrFindOrAdd(p->pStrs, pToken, NULL) );
    pToken = strtok( NULL, " ()" );
    assert( pToken == NULL );
    assert( *pLimit == 0 );
    *pLimit = ')';
    p->pCur = pLimit;
    return 1;
}
int Prs_SmtReadLines( Prs_Smt_t * p )
{
    int fAssert = 0;
    Prs_SmtSkipSpaces( p );
    while ( *p->pCur == '(' )
    {
        p->pCur++;
        if ( Prs_SmtIsWord(p, "let") )
        {
            assert( *p->pCur == '(' );
            p->pCur++;
            if ( !Prs_SmtParseLet( p, Prs_SmtFindNextPar(p), PRS_SMT_LET ) )
                return 0;
            assert( *p->pCur == ')' );
            p->pCur++;
        }
        else if ( Prs_SmtIsWord(p, "declare-fun")  )
        {
            if ( !Prs_SmtParseFun( p, Prs_SmtFindNextPar(p), PRS_SMT_INPUT ) )
                return 0;
            assert( *p->pCur == ')' );
            p->pCur++;
        }
        else if ( Prs_SmtIsWord(p, "define-fun") )
        {
            if ( !Prs_SmtParseFun( p, Prs_SmtFindNextPar(p), PRS_SMT_CONST ) )
                return 0;
            assert( *p->pCur == ')' );
            p->pCur++;
        }
        else if ( Prs_SmtIsWord(p, "get-value") )
        {
            if ( !Prs_SmtParseValue( p, Prs_SmtFindNextPar(p), PRS_SMT_VALUE ) )
                return 0;
            assert( *p->pCur == ')' );
            p->pCur++;
        }
        else if ( Prs_SmtIsWord(p, "assert") )
            fAssert = 1;
        else if ( Prs_SmtIsWord(p, "check-sat") )
            break;
        else if ( Prs_SmtIsWord(p, "set-option") || Prs_SmtIsWord(p, "set-logic") )
            p->pCur = Prs_SmtFindNextPar(p) + 1;
//        else
            //return Prs_SmtErrorSet(p, "Unsupported directive.", 0);
        Prs_SmtSkipSpaces( p );
        if ( *p->pCur != '(' && fAssert == 1 )
        {
            fAssert = 0;
            // finish parsing assert
            if ( !Prs_SmtParseLet( p, Prs_SmtFindNextPar(p), PRS_SMT_ASSERT ) )
                return 0;
            assert( *p->pCur == ')' );
            Vec_IntPush( &p->vData, 0 );
            // skip closing
            while ( *p->pCur == ')' )
                p->pCur++;
            Prs_SmtSkipSpaces( p );
        }
    }
    assert( fAssert == 0 );
    return 1;
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Prs_SmtPrintParser( Prs_Smt_t * p )
{
    int Entry, i;
    Vec_IntForEachEntry( &p->vData, Entry, i )
    {
        if ( Entry == 0 )
        {
            printf( "\n" );
            if ( i == Vec_IntSize(&p->vData) - 1 )
                break;
            Entry = Vec_IntEntry(&p->vData, ++i);
            if ( Entry == PRS_SMT_INPUT )
                printf( "declare-fun" );
            else if ( Entry == PRS_SMT_CONST )
                printf( "define-fun" );
            else if ( Entry == PRS_SMT_LET )
                printf( "let" );
            else if ( Entry == PRS_SMT_ASSERT )
                printf( "assert" );
            else assert(0);
            continue;
        }
        printf( " %s", Abc_NamStr(p->pStrs, Entry) );
    }
    Vec_IntForEachEntry( &p->vValues, Entry, i )
        printf( "get-value %s\n", Abc_NamStr(p->pStrs, Entry) );
}



/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Prs_SmtReadConstant( Wlc_Ntk_t * pNtk, char * pStr, int nBits, Vec_Int_t * vFanins, char * pName )
{
    char Buffer[100];
    int i, nDigits, iObj, NameId, fFound;
    Vec_IntClear( vFanins );
    if ( pStr[0] != '#' )
    {
        // handle decimal number
        int Number = atoi( pStr );
        nBits = Abc_Base2Log( Number+1 );
        assert( nBits < 32 );
        Vec_IntPush( vFanins, Number );
    }
    else if ( pStr[1] == 'b' )
    {
        if ( nBits == -1 )
            nBits = strlen(pStr+2);
        Vec_IntFill( vFanins, Abc_BitWordNum(nBits), 0 );
        for ( i = 0; i < nBits; i++ )
            if ( pStr[2+i] == '1' )
                Abc_InfoSetBit( (unsigned *)Vec_IntArray(vFanins), nBits-1-i );
            else if ( pStr[2+i] != '0' )
                return 0;
    }
    else if ( pStr[1] == 'x' )
    {
        if ( nBits == -1 )
            nBits = strlen(pStr+2)*4;
        Vec_IntFill( vFanins, Abc_BitWordNum(nBits), 0 );
        nDigits = Abc_TtReadHexNumber( (word *)Vec_IntArray(vFanins), pStr+2 );
        if ( nDigits != (nBits + 3)/4 )
            assert( 0 );
    }
    else return 0;
    // create constant node
    iObj = Wlc_ObjAlloc( pNtk, WLC_OBJ_CONST, 0, nBits-1, 0 );
    Wlc_ObjAddFanins( pNtk, Wlc_NtkObj(pNtk, iObj), vFanins );
    // add node's name
    if ( pName == NULL )
    {
        sprintf( Buffer, "_c%d_", iObj );
        pName = Buffer;
    }
    NameId = Abc_NamStrFindOrAdd( pNtk->pManName, pName, &fFound );
    assert( !fFound );
    assert( iObj == NameId );
    return NameId;
}
static inline int Prs_SmtReadName( Wlc_Ntk_t * pNtk, char * pStr, int nBits, Vec_Int_t * vFanins )
{
    if ( (pStr[0] >= '0' && pStr[0] <= '9') || pStr[0] == '#' )
    {
        Vec_Int_t * vTemp = Vec_IntAlloc(0);
        int NameId = Prs_SmtReadConstant( pNtk, pStr, nBits, vTemp, NULL );
        Vec_IntFree( vTemp );
        if ( !NameId )
            return 0;
        Vec_IntPush( vFanins, NameId );
        return 1;
    }
    else
    {
        // read name
        int fFound, NameId = Abc_NamStrFindOrAdd( pNtk->pManName, pStr, &fFound );
        assert( fFound );
        Vec_IntPush( vFanins, NameId );
        return 1;
    }
}
static inline int Prs_SmtStrToType( char * pName, int * pfSigned )
{
    int Type = 0; *pfSigned = 0;
    if ( !strcmp(pName, "ite") )
        Type = WLC_OBJ_MUX;           // 08: multiplexer
    else if ( !strcmp(pName, "bvlshr") )
        Type = WLC_OBJ_SHIFT_R;       // 09: shift right
    else if ( !strcmp(pName, "bvashr") )
        Type = WLC_OBJ_SHIFT_RA;      // 10: shift right (arithmetic)
    else if ( !strcmp(pName, "bvshl") )
        Type = WLC_OBJ_SHIFT_L;       // 11: shift left
//    else if ( !strcmp(pName, "") )
//        Type = WLC_OBJ_SHIFT_LA;    // 12: shift left (arithmetic)
    else if ( !strcmp(pName, "rotate_right") )
        Type = WLC_OBJ_ROTATE_R;      // 13: rotate right
    else if ( !strcmp(pName, "rotate_left") )
        Type = WLC_OBJ_ROTATE_L;      // 14: rotate left
    else if ( !strcmp(pName, "bvnot") )
        Type = WLC_OBJ_BIT_NOT;       // 15: bitwise NOT
    else if ( !strcmp(pName, "bvand") )
        Type = WLC_OBJ_BIT_AND;       // 16: bitwise AND
    else if ( !strcmp(pName, "bvor") )
        Type = WLC_OBJ_BIT_OR;        // 17: bitwise OR
    else if ( !strcmp(pName, "bvxor") )
        Type = WLC_OBJ_BIT_XOR;       // 18: bitwise XOR
    else if ( !strcmp(pName, "extract") )
        Type = WLC_OBJ_BIT_SELECT;    // 19: bit selection
    else if ( !strcmp(pName, "concat") )
        Type = WLC_OBJ_BIT_CONCAT;    // 20: bit concatenation
    else if ( !strcmp(pName, "zero_extend") )
        Type = WLC_OBJ_BIT_ZEROPAD;   // 21: zero padding
    else if ( !strcmp(pName, "sign_extend") )
        Type = WLC_OBJ_BIT_SIGNEXT, *pfSigned = 1;   // 22: sign extension
    else if ( !strcmp(pName, "not") )
        Type = WLC_OBJ_LOGIC_NOT;     // 23: logic NOT
    else if ( !strcmp(pName, "and") )
        Type = WLC_OBJ_LOGIC_AND;     // 24: logic AND
    else if ( !strcmp(pName, "or") )
        Type = WLC_OBJ_LOGIC_OR;      // 25: logic OR
    else if ( !strcmp(pName, "xor") )
        Type = WLC_OBJ_LOGIC_XOR;     // 26: logic OR
    else if ( !strcmp(pName, "bvcomp") )
        Type = WLC_OBJ_COMP_EQU;      // 27: compare equal
//    else if ( !strcmp(pName, "") )
//        Type = WLC_OBJ_COMP_NOTEQU;   // 28: compare not equal
    else if ( !strcmp(pName, "bvult") )
        Type = WLC_OBJ_COMP_LESS;     // 29: compare less
    else if ( !strcmp(pName, "bvugt") )
        Type = WLC_OBJ_COMP_MORE;     // 30: compare more
    else if ( !strcmp(pName, "bvule") )
        Type = WLC_OBJ_COMP_LESSEQU;  // 31: compare less or equal
    else if ( !strcmp(pName, "bvuge") )
        Type = WLC_OBJ_COMP_MOREEQU;  // 32: compare more or equal
    else if ( !strcmp(pName, "bvslt") )
        Type = WLC_OBJ_COMP_LESS, *pfSigned = 1;     // 29: compare less
    else if ( !strcmp(pName, "bvsgt") )
        Type = WLC_OBJ_COMP_MORE, *pfSigned = 1;     // 30: compare more
    else if ( !strcmp(pName, "bvsle") )
        Type = WLC_OBJ_COMP_LESSEQU, *pfSigned = 1;  // 31: compare less or equal
    else if ( !strcmp(pName, "bvsge") )
        Type = WLC_OBJ_COMP_MOREEQU, *pfSigned = 1;  // 32: compare more or equal
    else if ( !strcmp(pName, "bvredand") )
        Type = WLC_OBJ_REDUCT_AND;    // 33: reduction AND
    else if ( !strcmp(pName, "bvredor") )
        Type = WLC_OBJ_REDUCT_OR;     // 34: reduction OR
    else if ( !strcmp(pName, "bvredxor") )
        Type = WLC_OBJ_REDUCT_XOR;    // 35: reduction XOR
    else if ( !strcmp(pName, "bvadd") )
        Type = WLC_OBJ_ARI_ADD;       // 36: arithmetic addition
    else if ( !strcmp(pName, "bvsub") )
        Type = WLC_OBJ_ARI_SUB;       // 37: arithmetic subtraction
    else if ( !strcmp(pName, "bvmul") )
        Type = WLC_OBJ_ARI_MULTI;     // 38: arithmetic multiplier
    else if ( !strcmp(pName, "bvudiv") )
        Type = WLC_OBJ_ARI_DIVIDE;    // 39: arithmetic division
    else if ( !strcmp(pName, "bvurem") )
        Type = WLC_OBJ_ARI_MODULUS;   // 40: arithmetic modulus
    else if ( !strcmp(pName, "bvsdiv") )
        Type = WLC_OBJ_ARI_DIVIDE, *pfSigned = 1;    // 39: arithmetic division
    else if ( !strcmp(pName, "bvsrem") )
        Type = WLC_OBJ_ARI_MODULUS, *pfSigned = 1;   // 40: arithmetic modulus
    else if ( !strcmp(pName, "bvsmod") )
        Type = WLC_OBJ_ARI_MODULUS, *pfSigned = 1;   // 40: arithmetic modulus
//    else if ( !strcmp(pName, "") )
//        Type = WLC_OBJ_ARI_POWER;     // 41: arithmetic power
    else if ( !strcmp(pName, "bvneg") )
        Type = WLC_OBJ_ARI_MINUS;       // 42: arithmetic minus
//    else if ( !strcmp(pName, "") )
//        Type = WLC_OBJ_TABLE;         // 43: bit table
    else
    {
        printf( "The following operations is currently not supported (%s)\n", pName );
        fflush( stdout );
        assert( 0 );
    }
    return Type;
}
static inline int Prs_SmtReadNode( Prs_Smt_t * p, Wlc_Ntk_t * pNtk, Vec_Int_t * vData, int i, Vec_Int_t * vFanins, int * pRange, int * pfSigned )
{
    int Type, NameId;
    char * pName = Abc_NamStr( p->pStrs, Vec_IntEntry(vData, i) );
    // read type
    Type = Prs_SmtStrToType( pName, pfSigned );
    if ( Type == 0 )
        return 0;
    *pRange = 0;
    Vec_IntClear( vFanins );
    if ( Type == WLC_OBJ_COMP_EQU )
    {
        *pRange = 1;
        Prs_SmtReadName( pNtk, Abc_NamStr(p->pStrs, Vec_IntEntry(vData, ++i)), -1, vFanins );
        Prs_SmtReadName( pNtk, Abc_NamStr(p->pStrs, Vec_IntEntry(vData, ++i)), -1, vFanins );
        return WLC_OBJ_COMP_EQU;
    }
    else if ( Type == WLC_OBJ_LOGIC_NOT )
    {
        pName = Abc_NamStr( p->pStrs, Vec_IntEntry(vData, ++i) );
        if ( !strcmp(pName, "bvcomp") )
        {
            *pRange = 1;
            Prs_SmtReadName( pNtk, Abc_NamStr(p->pStrs, Vec_IntEntry(vData, ++i)), -1, vFanins );
            Prs_SmtReadName( pNtk, Abc_NamStr(p->pStrs, Vec_IntEntry(vData, ++i)), -1, vFanins );
            return WLC_OBJ_COMP_NOTEQU;   // 26: compare equal
        }
        i--;
    }
    else if ( Type == WLC_OBJ_BIT_SELECT )
    {
        int End, Beg;
        pName = Abc_NamStr( p->pStrs, Vec_IntEntry(vData, ++i) );
        End = atoi( pName );
        pName = Abc_NamStr( p->pStrs, Vec_IntEntry(vData, ++i) );
        Beg = atoi( pName );
        pName = Abc_NamStr( p->pStrs, Vec_IntEntry(vData, ++i) );
        Prs_SmtReadName( pNtk, pName, -1, vFanins );
        Vec_IntPush( vFanins, (End << 16) | Beg );
        *pRange = End - Beg + 1;
        return WLC_OBJ_BIT_SELECT;
    }
    while ( Vec_IntEntry(vData, ++i) )
        Prs_SmtReadName( pNtk, Abc_NamStr(p->pStrs, Vec_IntEntry(vData, i)), -1, vFanins );
    if ( Type == WLC_OBJ_ROTATE_R || Type == WLC_OBJ_ROTATE_L )
    {
        int * pArray = Vec_IntArray(vFanins);
        assert( Vec_IntSize(vFanins) == 2 );
        ABC_SWAP( int, pArray[0], pArray[1] );
    }    
    if ( Type >= WLC_OBJ_LOGIC_NOT && Type <= WLC_OBJ_REDUCT_XOR )
        *pRange = 1;
    else if ( Type == WLC_OBJ_BIT_CONCAT )
    {
        int k;
        Vec_IntForEachEntry( vFanins, NameId, k )
            *pRange += Wlc_ObjRange( Wlc_NtkObj(pNtk, NameId) );
    }
    else if ( Type == WLC_OBJ_MUX )
    {
        int * pArray = Vec_IntArray(vFanins);
        assert( Vec_IntSize(vFanins) == 3 );
        ABC_SWAP( int, pArray[1], pArray[2] );
        NameId = Vec_IntEntry(vFanins, 1);
        *pRange = Wlc_ObjRange( Wlc_NtkObj(pNtk, NameId) );
    }
    else // to determine range, look at the first argument
    {
        NameId = Vec_IntEntry(vFanins, 0);
        *pRange = Wlc_ObjRange( Wlc_NtkObj(pNtk, NameId) );
    }
    return Type;
}
Wlc_Ntk_t * Prs_SmtBuild( Prs_Smt_t * p )
{
    Wlc_Ntk_t * pNtk;
    char * pName, * pBits, * pConst;
    Vec_Int_t * vFanins = Vec_IntAlloc( 100 );
    int i, iObj, Type, Entry, NameId, fFound, Range, fSigned, nBits = 0;
    // start network and create primary inputs
    pNtk = Wlc_NtkAlloc( p->pName, Vec_IntCountEntry(&p->vData, 0) + 100 );
    pNtk->pManName = Abc_NamStart( 1000, 24 );
    for ( i = 0; i < Vec_IntSize(&p->vData) - 1; )
    {
        assert( Vec_IntEntry(&p->vData, i) == 0 );
        if ( Vec_IntEntry(&p->vData, ++i) == PRS_SMT_INPUT )
        {
            pName = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            pBits = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            iObj = Wlc_ObjAlloc( pNtk, WLC_OBJ_PI, 0, atoi(pBits)-1, 0 );
            NameId = Abc_NamStrFindOrAdd( pNtk->pManName, pName, &fFound );
            assert( !fFound );
            assert( iObj == NameId );
            // save values
            Vec_IntPush( &pNtk->vValues, NameId );
            Vec_IntPush( &pNtk->vValues, nBits );
            Vec_IntPush( &pNtk->vValues, atoi(pBits) );
            nBits += atoi(pBits);
        }
        while ( Vec_IntEntry(&p->vData, ++i) );
    }
    // create logic nodes
    for ( i = 0; i < Vec_IntSize(&p->vData) - 1; )
    {
        assert( Vec_IntEntry(&p->vData, i) == 0 );
        Entry = Vec_IntEntry(&p->vData, ++i);
        if ( Entry == PRS_SMT_INPUT )
        {}
        else if ( Entry == PRS_SMT_CONST )
        {
            pName  = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            pBits  = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            pConst = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            // create new node
            if ( !Prs_SmtReadConstant( pNtk, pConst, atoi(pBits), vFanins, pName ) )
                return NULL;
        }
        else if ( Entry == PRS_SMT_LET )
        {
            pName = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            Type = Prs_SmtReadNode( p, pNtk, &p->vData, ++i, vFanins, &Range, &fSigned );
            if ( Type == WLC_OBJ_NONE )
                return NULL;
            assert( Range > 0 );
            // create new node
            iObj = Wlc_ObjAlloc( pNtk, Type, 0, Range-1, 0 );
            Wlc_ObjAddFanins( pNtk, Wlc_NtkObj(pNtk, iObj), vFanins );
            if ( fSigned )
            {
                Wlc_NtkObj(pNtk, iObj)->Signed = fSigned;
                if ( Vec_IntSize(vFanins) > 0 )
                    Wlc_NtkObj(pNtk, Vec_IntEntry(vFanins, 0))->Signed = fSigned;
                if ( Vec_IntSize(vFanins) > 1 )
                    Wlc_NtkObj(pNtk, Vec_IntEntry(vFanins, 1))->Signed = fSigned;
            }
            // add node's name
            NameId = Abc_NamStrFindOrAdd( pNtk->pManName, pName, &fFound );
            assert( !fFound );
            assert( iObj == NameId );
        }
        else if ( Entry == PRS_SMT_ASSERT )
        {
            Type = WLC_OBJ_BUF;
            Vec_IntClear( vFanins );
            pName = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
            if ( !strcmp(pName, "not") )
            {
                Type = WLC_OBJ_LOGIC_NOT;
                pName = Abc_NamStr( p->pStrs, Vec_IntEntry(&p->vData, ++i) );
                Range = 1;
            }
            // add fanin
            NameId = Abc_NamStrFindOrAdd( pNtk->pManName, pName, &fFound );
            assert( fFound );
            Vec_IntPush( vFanins, NameId );
            // find range
            if ( Type == WLC_OBJ_BUF )
            {
                // find range
                iObj = Vec_IntEntry(vFanins, 0);
                Range = Wlc_ObjRange( Wlc_NtkObj(pNtk, iObj) );
                assert( Range == 1 );
            }
            // create new node
            iObj = Wlc_ObjAlloc( pNtk, Type, 0, Range-1, 0 );
            Wlc_ObjAddFanins( pNtk, Wlc_NtkObj(pNtk, iObj), vFanins );
            Wlc_ObjSetCo( pNtk, Wlc_NtkObj(pNtk, iObj), 0 );
            // add node's name
            NameId = Abc_NamStrFindOrAdd( pNtk->pManName, "miter_output", &fFound );
            assert( !fFound );
            assert( iObj == NameId );
            break;
        }
        else assert( 0 );
        while ( Vec_IntEntry(&p->vData, ++i) );
    }
    Vec_IntFree( vFanins );
    // create nameIDs
    vFanins = Vec_IntStartNatural( Wlc_NtkObjNumMax(pNtk) );
    Vec_IntAppend( &pNtk->vNameIds, vFanins );
    Vec_IntFree( vFanins );
    //Wlc_NtkReport( pNtk, NULL );
    return pNtk;
}
Wlc_Ntk_t * Wlc_ReadSmtBuffer( char * pFileName, char * pBuffer, char * pLimit )
{
    Wlc_Ntk_t * pNtk = NULL;
    Prs_Smt_t * p = Prs_SmtAlloc( pFileName, pBuffer, pLimit );
    if ( p == NULL )
        return NULL;
    Prs_SmtRemoveComments( p );
    Prs_SmtReadLines( p );
    //Prs_SmtPrintParser( p );
    if ( Prs_SmtErrorPrint(p) )
        pNtk = Prs_SmtBuild( p );
    Prs_SmtFree( p );
    return pNtk;
}
Wlc_Ntk_t * Wlc_ReadSmt( char * pFileName )
{
    Wlc_Ntk_t * pNtk = NULL;
    char * pBuffer, * pLimit;
    pBuffer = Prs_SmtLoadFile( pFileName, &pLimit );
    if ( pBuffer == NULL )
        return NULL;
    pNtk = Wlc_ReadSmtBuffer( pFileName, pBuffer, pLimit );
    ABC_FREE( pBuffer );
    return pNtk;
}

////////////////////////////////////////////////////////////////////////
///                       END OF FILE                                ///
////////////////////////////////////////////////////////////////////////


ABC_NAMESPACE_IMPL_END

