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

  FileName    [cbaReadVer.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Hierarchical word-level netlist.]

  Synopsis    [BLIF writer.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - November 29, 2014.]

  Revision    [$Id: cbaReadVer.c,v 1.00 2014/11/29 00:00:00 alanmi Exp $]

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

#include "cba.h"
#include "cbaPrs.h"

ABC_NAMESPACE_IMPL_START

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

// Verilog keywords
typedef enum { 
    PRS_VER_NONE = 0,  // 0:  unused
    PRS_VER_MODULE,    // 1:  module
    PRS_VER_INOUT,     // 2:  inout
    PRS_VER_INPUT,     // 3:  input
    PRS_VER_OUTPUT,    // 4:  output
    PRS_VER_WIRE,      // 5:  wire
    PRS_VER_ASSIGN,    // 6:  assign
    PRS_VER_REG,       // 7:  reg
    PRS_VER_ALWAYS,    // 8:  always
    PRS_VER_DEFPARAM,  // 9:  always
    PRS_VER_BEGIN,     // 10: begin
    PRS_VER_END,       // 11: end
    PRS_VER_ENDMODULE, // 12: endmodule
    PRS_VER_UNKNOWN    // 13: unknown
} Cba_VerType_t;

const char * s_VerTypes[PRS_VER_UNKNOWN+1] = {
    NULL,              // 0:  unused
    "module",          // 1:  module
    "inout",           // 2:  inout
    "input",           // 3:  input
    "output",          // 4:  output
    "wire",            // 5:  wire
    "assign",          // 6:  assign
    "reg",             // 7:  reg
    "always",          // 8:  always
    "defparam",        // 9:  defparam
    "begin",           // 10: begin
    "end",             // 11: end
    "endmodule",       // 12: endmodule
    NULL               // 13: unknown 
};

static inline void Prs_NtkAddVerilogDirectives( Prs_Man_t * p )
{
    int i;
    for ( i = 1; s_VerTypes[i]; i++ )
        Abc_NamStrFindOrAdd( p->pStrs, (char *)s_VerTypes[i],   NULL );
    assert( Abc_NamObjNumMax(p->pStrs) == i );
}


// character recognition 
static inline int Prs_CharIsSpace( char c )   { return (c == ' ' || c == '\t' || c == '\r' || c == '\n');                           }
static inline int Prs_CharIsDigit( char c )   { return (c >= '0' && c <= '9');                                                      }
static inline int Prs_CharIsDigitB( char c )  { return (c == '0' || c == '1'  || c == 'x' || c == 'z');                             }
static inline int Prs_CharIsDigitH( char c )  { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');  }
static inline int Prs_CharIsChar( char c )    { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');                            }
static inline int Prs_CharIsSymb1( char c )   { return Prs_CharIsChar(c) || c == '_';                                               }
static inline int Prs_CharIsSymb2( char c )   { return Prs_CharIsSymb1(c) || Prs_CharIsDigit(c) || c == '$';                        }

static inline int Prs_ManIsChar( Prs_Man_t * p, char c )    { return p->pCur[0] == c;                        }
static inline int Prs_ManIsChar1( Prs_Man_t * p, char c )   { return p->pCur[1] == c;                        }
static inline int Prs_ManIsDigit( Prs_Man_t * p )           { return Prs_CharIsDigit(*p->pCur);              }

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

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

// collect predefined modules names
const char * s_KnownModules[100] = {
    NULL,     // CBA_OBJ_NONE = 0,  // 0:  unused
    NULL,     // CBA_OBJ_PI,        // 1:  input
    NULL,     // CBA_OBJ_PO,        // 2:  output
    NULL,     // CBA_OBJ_BI,        // 3:  box input
    NULL,     // CBA_OBJ_BO,        // 4:  box output
    NULL,     // CBA_OBJ_BOX,       // 5:  box
 
    "const0", // CBA_BOX_C0,   
    "const1", // CBA_BOX_C1,   
    "constX", // CBA_BOX_CX,   
    "constZ", // CBA_BOX_CZ,   
    "buf",    // CBA_BOX_BUF,  
    "not",    // CBA_BOX_INV,  
    "and",    // CBA_BOX_AND,  
    "nand",   // CBA_BOX_NAND, 
    "or",     // CBA_BOX_OR,   
    "nor",    // CBA_BOX_NOR,  
    "xor",    // CBA_BOX_XOR,  
    "xnor",   // CBA_BOX_XNOR, 
    "sharp",  // CBA_BOX_SHARP,
    "mux",    // CBA_BOX_MUX,  
    "maj",    // CBA_BOX_MAJ,  

    "VERIFIC_",
    "add_",                  
    "mult_",                 
    "div_",                  
    "mod_",                  
    "rem_",                  
    "shift_left_",           
    "shift_right_",          
    "rotate_left_",          
    "rotate_right_",         
    "reduce_and_",           
    "reduce_or_",            
    "reduce_xor_",           
    "reduce_nand_",          
    "reduce_nor_",           
    "reduce_xnor_",          
    "LessThan_",             
    "Mux_",                  
    "Select_",               
    "Decoder_",              
    "EnabledDecoder_",       
    "PrioSelect_",           
    "DualPortRam_",          
    "ReadPort_",             
    "WritePort_",            
    "ClockedWritePort_",     
    "lut",                   
    "and_",                  
    "or_",                   
    "xor_",                  
    "nand_",                 
    "nor_",                  
    "xnor_",                 
    "buf_",                  
    "inv_",                  
    "tri_",                  
    "sub_",                  
    "unary_minus_",          
    "equal_",                
    "not_equal_",            
    "mux_",                  
    "wide_mux_",             
    "wide_select_",          
    "wide_dff_",             
    "wide_dlatch_",          
    "wide_dffrs_",           
    "wide_dlatchrs_",        
    "wide_prio_select_",     
    "pow_",                  
    "PrioEncoder_",          
    "abs",                   
    NULL
};

// check if it is a known module
static inline int Prs_ManIsKnownModule( Prs_Man_t * p, char * pName )
{
    int i;
    for ( i = CBA_BOX_C0; s_KnownModules[i]; i++ )
        if ( !strncmp(pName, s_KnownModules[i], strlen(s_KnownModules[i])) )
            return i;
    return 0;
}


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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

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

// skips Verilog comments (returns 1 if some comments were skipped)
static inline int Prs_ManUtilSkipComments( Prs_Man_t * p )
{
    if ( !Prs_ManIsChar(p, '/') )
        return 0;
    if ( Prs_ManIsChar1(p, '/') )
    {
        for ( p->pCur += 2; p->pCur < p->pLimit; p->pCur++ )
            if ( Prs_ManIsChar(p, '\n') )
                { p->pCur++; return 1; }
    }
    else if ( Prs_ManIsChar1(p, '*') )
    {
        for ( p->pCur += 2; p->pCur < p->pLimit; p->pCur++ )
            if ( Prs_ManIsChar(p, '*') && Prs_ManIsChar1(p, '/') )
                { p->pCur++; p->pCur++; return 1; }
    }
    return 0;
}
static inline int Prs_ManUtilSkipName( Prs_Man_t * p )
{
    if ( !Prs_ManIsChar(p, '\\') )
        return 0;
    for ( p->pCur++; p->pCur < p->pLimit; p->pCur++ )
        if ( Prs_ManIsChar(p, ' ') )
            { p->pCur++; return 1; }
    return 0;
}

// skip any number of spaces and comments
static inline int Prs_ManUtilSkipSpaces( Prs_Man_t * p )
{
    while ( p->pCur < p->pLimit )
    {
        while ( Prs_CharIsSpace(*p->pCur) ) 
            p->pCur++;
        if ( !*p->pCur )
            return Prs_ManErrorSet(p, "Unexpectedly reached end-of-file.", 1);
        if ( !Prs_ManUtilSkipComments(p) )
            return 0;
    }
    return Prs_ManErrorSet(p, "Unexpectedly reached end-of-file.", 1);
}
// skip everything including comments until the given char
static inline int Prs_ManUtilSkipUntil( Prs_Man_t * p, char c )
{
    while ( p->pCur < p->pLimit )
    {
        if ( Prs_ManIsChar(p, c) )
            return 1;
        if ( Prs_ManUtilSkipComments(p) )
            continue;
        if ( Prs_ManUtilSkipName(p) )
            continue;
        p->pCur++;
    }
    return 0;
}
// skip everything including comments until the given word
static inline int Prs_ManUtilSkipUntilWord( Prs_Man_t * p, char * pWord )
{
    char * pPlace = strstr( p->pCur, pWord );
    if ( pPlace == NULL )  return 1;
    p->pCur = pPlace + strlen(pWord);
    return 0;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Prs_ManReadName( Prs_Man_t * p )
{
    char * pStart = p->pCur;
    if ( Prs_ManIsChar(p, '\\') ) // escaped name
    {
        pStart = ++p->pCur;
        while ( !Prs_ManIsChar(p, ' ') ) 
            p->pCur++;
    }    
    else if ( Prs_CharIsSymb1(*p->pCur) ) // simple name
    {
        p->pCur++;
        while ( Prs_CharIsSymb2(*p->pCur) ) 
            p->pCur++;
    }
    else 
        return 0;
    return Abc_NamStrFindOrAddLim( p->pStrs, pStart, p->pCur, NULL );
}
static inline int Prs_ManReadNameList( Prs_Man_t * p, Vec_Int_t * vTemp, char LastSymb )
{
    Vec_IntClear( vTemp );
    while ( 1 )
    {
        int Item = Prs_ManReadName(p);
        if ( Item == 0 )                    return Prs_ManErrorSet(p, "Cannot read name in the list.", 0);
        Vec_IntPush( vTemp, Item );
        if ( Prs_ManIsChar(p, LastSymb) )   break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the list.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
    }
    return 1;
}
static inline int Prs_ManReadConstant( Prs_Man_t * p )
{
    char * pStart = p->pCur;
    assert( Prs_ManIsDigit(p) );
    while ( Prs_ManIsDigit(p) ) 
        p->pCur++;
    if ( !Prs_ManIsChar(p, '\'') )          return Prs_ManErrorSet(p, "Cannot read constant.", 0);
    p->pCur++;
    if ( Prs_ManIsChar(p, 'b') )
    {
        p->pCur++;
        while ( Prs_CharIsDigitB(*p->pCur) ) 
            p->pCur++;
    }
    else if ( Prs_ManIsChar(p, 'h') )
    {
        p->pCur++;
        while ( Prs_CharIsDigitH(*p->pCur) ) 
            p->pCur++;
    }
    else if ( Prs_ManIsChar(p, 'd') )
    {
        p->pCur++;
        while ( Prs_ManIsDigit(p) ) 
            p->pCur++;
    }
    else                                    return Prs_ManErrorSet(p, "Cannot read radix of constant.", 0);
    return Abc_NamStrFindOrAddLim( p->pStrs, pStart, p->pCur, NULL );
}
static inline int Prs_ManReadRange( Prs_Man_t * p )
{
    assert( Prs_ManIsChar(p, '[') );
    Vec_StrClear( &p->vCover );
    Vec_StrPush( &p->vCover, *p->pCur++ );
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( !Prs_ManIsDigit(p) )               return Prs_ManErrorSet(p, "Cannot read digit in range specification.", 0);
    while ( Prs_ManIsDigit(p) )
        Vec_StrPush( &p->vCover, *p->pCur++ );
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( Prs_ManIsChar(p, ':') )
    {
        Vec_StrPush( &p->vCover, *p->pCur++ );
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
        if ( !Prs_ManIsDigit(p) )           return Prs_ManErrorSet(p, "Cannot read digit in range specification.", 0);
        while ( Prs_ManIsDigit(p) )
            Vec_StrPush( &p->vCover, *p->pCur++ );
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
    }
    if ( !Prs_ManIsChar(p, ']') )           return Prs_ManErrorSet(p, "Cannot read closing brace in range specification.", 0);
    Vec_StrPush( &p->vCover, *p->pCur++ );
    Vec_StrPush( &p->vCover, '\0' );
    return Abc_NamStrFindOrAdd( p->pStrs, Vec_StrArray(&p->vCover), NULL );
}
static inline int Prs_ManReadConcat( Prs_Man_t * p, Vec_Int_t * vTemp2 )
{
    extern int Prs_ManReadSignalList( Prs_Man_t * p, Vec_Int_t * vTemp, char LastSymb, int fAddForm );
    assert( Prs_ManIsChar(p, '{') );
    p->pCur++;
    if ( !Prs_ManReadSignalList( p, vTemp2, '}', 0 ) ) return 0;
    // check final
    assert( Prs_ManIsChar(p, '}') );
    p->pCur++;
    // return special case
    assert( Vec_IntSize(vTemp2) > 0 );
    if ( Vec_IntSize(vTemp2) == 1 )
        return Vec_IntEntry(vTemp2, 0);
    return Abc_Var2Lit2( Prs_NtkAddConcat(p->pNtk, vTemp2), CBA_PRS_CONCAT );
}
static inline int Prs_ManReadSignal( Prs_Man_t * p )
{
    int Item;
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( Prs_ManIsDigit(p) )
    {
        Item = Prs_ManReadConstant(p);
        if ( Item == 0 )                    return 0;
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
        return Abc_Var2Lit2( Item, CBA_PRS_CONST );
    }
    if ( Prs_ManIsChar(p, '{') )
    {
        if ( p->fUsingTemp2 )               return Prs_ManErrorSet(p, "Cannot read nested concatenations.", 0);
        p->fUsingTemp2 = 1;
        Item = Prs_ManReadConcat(p, &p->vTemp2);
        p->fUsingTemp2 = 0;
        if ( Item == 0 )                    return 0;
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
        return Item;
    }
    else
    {
        Item = Prs_ManReadName( p );
        if ( Item == 0 )                    return 0;    // was        return 1;                
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
        if ( Prs_ManIsChar(p, '[') )
        {
            int Range = Prs_ManReadRange(p);
            if ( Range == 0 )               return 0;
            if ( Prs_ManUtilSkipSpaces(p) ) return 0;
            return Abc_Var2Lit2( Prs_NtkAddSlice(p->pNtk, Item, Range), CBA_PRS_SLICE );
        }
        return Abc_Var2Lit2( Item, CBA_PRS_NAME );
    }
}
static inline int Prs_ManReadSignalList( Prs_Man_t * p, Vec_Int_t * vTemp, char LastSymb, int fAddForm )
{
    Vec_IntClear( vTemp );
    while ( 1 )
    {
        int Item = Prs_ManReadSignal(p);
        if ( Item == 0 )                    return Prs_ManErrorSet(p, "Cannot read signal in the list.", 0);
        if ( fAddForm )
            Vec_IntPush( vTemp, 0 );
        Vec_IntPush( vTemp, Item );
        if ( Prs_ManIsChar(p, LastSymb) )   break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the list.", 0);
        p->pCur++;
    }
    return 1;
}
static inline int Prs_ManReadSignalList2( Prs_Man_t * p, Vec_Int_t * vTemp )
{
    int FormId, ActItem;
    Vec_IntClear( vTemp );
    assert( Prs_ManIsChar(p, '.') );
    while ( Prs_ManIsChar(p, '.') )
    {
        p->pCur++;
        FormId = Prs_ManReadName( p );
        if ( FormId == 0 )                  return Prs_ManErrorSet(p, "Cannot read formal name of the instance.", 0);
        if ( !Prs_ManIsChar(p, '(') )       return Prs_ManErrorSet(p, "Cannot read \"(\" in the instance.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
        ActItem = Prs_ManReadSignal( p );
        if ( ActItem == 0 )                 return Prs_ManErrorSet(p, "Cannot read actual name of the instance.", 0);
        if ( !Prs_ManIsChar(p, ')') )       return Prs_ManErrorSet(p, "Cannot read \")\" in the instance.", 0);
        p->pCur++;
        Vec_IntPushTwo( vTemp, FormId, ActItem );
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
        if ( Prs_ManIsChar(p, ')') )        break;
        if ( !Prs_ManIsChar(p, ',') )       return Prs_ManErrorSet(p, "Expecting comma in the instance.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return 0;
    }
    assert( Vec_IntSize(vTemp) > 0 );
    assert( Vec_IntSize(vTemp) % 2 == 0 );
    return 1;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Prs_ManReadDeclaration( Prs_Man_t * p, int Type )
{
    int i, Sig, RangeId = 0;
    Vec_Int_t * vSigs[4]  = { &p->pNtk->vInouts,  &p->pNtk->vInputs,  &p->pNtk->vOutputs,  &p->pNtk->vWires };
    Vec_Int_t * vSigsR[4] = { &p->pNtk->vInoutsR, &p->pNtk->vInputsR, &p->pNtk->vOutputsR, &p->pNtk->vWiresR };
    assert( Type >= PRS_VER_INOUT && Type <= PRS_VER_WIRE );
    if ( Prs_ManUtilSkipSpaces(p) )                                   return 0;
    if ( Prs_ManIsChar(p, '[') && !(RangeId = Prs_ManReadRange(p)) )  return 0;
    if ( !Prs_ManReadNameList( p, &p->vTemp, ';' ) )                  return 0;
    Vec_IntForEachEntry( &p->vTemp, Sig, i )
    {
        Vec_IntPush( vSigs[Type - PRS_VER_INOUT], Sig );
        Vec_IntPush( vSigsR[Type - PRS_VER_INOUT], RangeId );
    }
    return 1;
}
static inline int Prs_ManReadAssign( Prs_Man_t * p )
{
    int OutItem, InItem, fCompl = 0, Oper = 0;
    // read output name
    OutItem = Prs_ManReadSignal( p );
    if ( OutItem == 0 )                     return Prs_ManErrorSet(p, "Cannot read output in assign-statement.", 0);
    if ( !Prs_ManIsChar(p, '=') )           return Prs_ManErrorSet(p, "Expecting \"=\" in assign-statement.", 0);
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( Prs_ManIsChar(p, '~') ) 
    { 
        fCompl = 1; 
        p->pCur++; 
    }
    // read first name
    InItem = Prs_ManReadSignal( p );
    if ( InItem == 0 )                      return Prs_ManErrorSet(p, "Cannot read first input name in the assign-statement.", 0);
    Vec_IntClear( &p->vTemp );
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, InItem );
    // check unary operator
    if ( Prs_ManIsChar(p, ';') )
    {
        Vec_IntPush( &p->vTemp, 0 );
        Vec_IntPush( &p->vTemp, OutItem );
        Oper = fCompl ? CBA_BOX_INV : CBA_BOX_BUF;
        Prs_NtkAddBox( p->pNtk, Oper, 0, &p->vTemp );
        return 1;
    }
    if ( Prs_ManIsChar(p, '&') ) 
        Oper = CBA_BOX_AND;
    else if ( Prs_ManIsChar(p, '|') ) 
        Oper = CBA_BOX_OR;
    else if ( Prs_ManIsChar(p, '^') ) 
        Oper = fCompl ? CBA_BOX_XNOR : CBA_BOX_XOR;
    else if ( Prs_ManIsChar(p, '?') ) 
        Oper = CBA_BOX_MUX;
    else                                    return Prs_ManErrorSet(p, "Unrecognized operator in the assign-statement.", 0);
    p->pCur++; 
    // read second name
    InItem = Prs_ManReadSignal( p );
    if ( InItem == 0 )                      return Prs_ManErrorSet(p, "Cannot read second input name in the assign-statement.", 0);
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, InItem );
    // read third argument
    if ( Oper == CBA_BOX_MUX )
    {
        assert( fCompl == 0 ); 
        if ( !Prs_ManIsChar(p, ':') )       return Prs_ManErrorSet(p, "Expected colon in the MUX assignment.", 0);
        p->pCur++; 
        // read third name
        InItem = Prs_ManReadSignal( p );
        if ( InItem == 0 )                  return Prs_ManErrorSet(p, "Cannot read third input name in the assign-statement.", 0);
        Vec_IntPush( &p->vTemp, 0 );
        Vec_IntPush( &p->vTemp, InItem );
        if ( !Prs_ManIsChar(p, ';') )       return Prs_ManErrorSet(p, "Expected semicolon at the end of the assign-statement.", 0);
    }
    // write binary operator
    Vec_IntPush( &p->vTemp, 0 );
    Vec_IntPush( &p->vTemp, OutItem );
    Prs_NtkAddBox( p->pNtk, Oper, 0, &p->vTemp );
    return 1;
}
static inline int Prs_ManReadInstance( Prs_Man_t * p, int Func )
{
    int InstId, Status;
/*
    static Counter = 0;
    if ( ++Counter == 7 )
    {
        int s=0;
    }
*/
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( (InstId = Prs_ManReadName(p)) )
        if (Prs_ManUtilSkipSpaces(p))       return 0;
    if ( !Prs_ManIsChar(p, '(') )           return Prs_ManErrorSet(p, "Expecting \"(\" in module instantiation.", 0);
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( Prs_ManIsChar(p, '.') ) // box
        Status = Prs_ManReadSignalList2(p, &p->vTemp);
    else  // node
    {
        //char * s = Abc_NamStr(p->pStrs, Func);
        // translate elementary gate
        int iFuncNew = Prs_ManIsKnownModule(p, Abc_NamStr(p->pStrs, Func));
        if ( iFuncNew == 0 )                return Prs_ManErrorSet(p, "Cannot find elementary gate.", 0);
        Func = iFuncNew;
        Status = Prs_ManReadSignalList( p, &p->vTemp, ')', 1 );
    }
    if ( Status == 0 )                      return 0;
    assert( Prs_ManIsChar(p, ')') );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    if ( !Prs_ManIsChar(p, ';') )           return Prs_ManErrorSet(p, "Expecting semicolon in the instance.", 0);
    // add box 
    Prs_NtkAddBox( p->pNtk, Func, InstId, &p->vTemp );
    return 1;
}
static inline int Prs_ManReadArguments( Prs_Man_t * p )
{
    int iRange = 0, iType = -1;
    Vec_Int_t * vSigs[3]  = { &p->pNtk->vInouts,  &p->pNtk->vInputs,  &p->pNtk->vOutputs };
    Vec_Int_t * vSigsR[3] = { &p->pNtk->vInoutsR, &p->pNtk->vInputsR, &p->pNtk->vOutputsR };
    assert( Prs_ManIsChar(p, '(') );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )             return 0;
    while ( 1 )
    {
        int iName = Prs_ManReadName( p );
        if ( iName == 0 )                       return 0;
        if ( Prs_ManUtilSkipSpaces(p) )         return 0;
        if ( iName >= PRS_VER_INOUT && iName <= PRS_VER_OUTPUT ) // declaration
        {
            iType = iName;
            if ( Prs_ManIsChar(p, '[') )
            {
                iRange = Prs_ManReadRange(p);
                if ( iRange == 0 )              return 0;
                if ( Prs_ManUtilSkipSpaces(p) ) return 0;
            }
        }
        if ( iType > 0 )
        {
            Vec_IntPush( vSigs[iType - PRS_VER_INOUT], iName );
            Vec_IntPush( vSigsR[iType - PRS_VER_INOUT], iRange );
        }
        Vec_IntPush( &p->pNtk->vOrder, iName );
        if ( Prs_ManIsChar(p, ')') )
            break;
        if ( !Prs_ManIsChar(p, ',') )           return Prs_ManErrorSet(p, "Expecting comma in the instance.", 0);
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )         return 0;
    }
    // check final
    assert( Prs_ManIsChar(p, ')') );
    return 1;
}
// this procedure can return:
// 0 = reached end-of-file; 1 = successfully parsed; 2 = recognized as primitive; 3 = failed and skipped; 4 = error (failed and could not skip)
static inline int Prs_ManReadModule( Prs_Man_t * p )
{
    int iToken, Status;
    if ( p->pNtk != NULL )                  return Prs_ManErrorSet(p, "Parsing previous module is unfinished.", 4);
    if ( Prs_ManUtilSkipSpaces(p) )
    { 
        Prs_ManErrorClear( p );       
        return 0; 
    }
    // read keyword
    iToken = Prs_ManReadName( p );
    if ( iToken != PRS_VER_MODULE )         return Prs_ManErrorSet(p, "Cannot read \"module\" keyword.", 4);
    if ( Prs_ManUtilSkipSpaces(p) )         return 4;
    // read module name
    iToken = Prs_ManReadName( p );
    if ( iToken == 0 )                      return Prs_ManErrorSet(p, "Cannot read module name.", 4);
    if ( Prs_ManIsKnownModule(p, Abc_NamStr(p->pStrs, iToken)) )
    {
        if ( Prs_ManUtilSkipUntilWord( p, "endmodule" ) ) return Prs_ManErrorSet(p, "Cannot find \"endmodule\" keyword.", 4);
        //printf( "Warning! Skipped known module \"%s\".\n", Abc_NamStr(p->pStrs, iToken) );
        Vec_IntPush( &p->vKnown, iToken );
        return 2;
    }
    Prs_ManInitializeNtk( p, iToken, 1 );
    // skip arguments
    if ( Prs_ManUtilSkipSpaces(p) )         return 4;
    if ( !Prs_ManIsChar(p, '(') )           return Prs_ManErrorSet(p, "Cannot find \"(\" in the argument declaration.", 4);
    if ( !Prs_ManReadArguments(p) )         return 4;
    assert( *p->pCur == ')' );
    p->pCur++;
    if ( Prs_ManUtilSkipSpaces(p) )         return 4;
    // read declarations and instances
    while ( Prs_ManIsChar(p, ';') )
    {
        p->pCur++;
        if ( Prs_ManUtilSkipSpaces(p) )     return 4;
        iToken = Prs_ManReadName( p );
        if ( iToken == PRS_VER_ENDMODULE )
        {
            Vec_IntPush( &p->vSucceeded, p->pNtk->iModuleName );
            Prs_ManFinalizeNtk( p );
            return 1;
        }
        if ( iToken >= PRS_VER_INOUT && iToken <= PRS_VER_WIRE ) // declaration
            Status = Prs_ManReadDeclaration( p, iToken );
        else if ( iToken == PRS_VER_REG || iToken == PRS_VER_DEFPARAM ) // unsupported keywords
            Status = Prs_ManUtilSkipUntil( p, ';' );
        else // read instance
        {
            if ( iToken == PRS_VER_ASSIGN )
                Status = Prs_ManReadAssign( p );
            else
                Status = Prs_ManReadInstance( p, iToken );
            if ( Status == 0 )
            {
                if ( Prs_ManUtilSkipUntilWord( p, "endmodule" ) ) return Prs_ManErrorSet(p, "Cannot find \"endmodule\" keyword.", 4);
                //printf( "Warning! Failed to parse \"%s\". Adding module \"%s\" as blackbox.\n", 
                //    Abc_NamStr(p->pStrs, iToken), Abc_NamStr(p->pStrs, p->pNtk->iModuleName) );
                Vec_IntPush( &p->vFailed, p->pNtk->iModuleName );
                // cleanup
                Vec_IntErase( &p->pNtk->vWires );
                Vec_IntErase( &p->pNtk->vWiresR );
                Vec_IntErase( &p->pNtk->vSlices );
                Vec_IntErase( &p->pNtk->vConcats );
                Vec_IntErase( &p->pNtk->vBoxes );
                Vec_IntErase( &p->pNtk->vObjs );
                p->fUsingTemp2 = 0;
                // add
                Prs_ManFinalizeNtk( p );
                Prs_ManErrorClear( p );
                return 3;
            }
        }
        if ( !Status )                      return 4;
        if ( Prs_ManUtilSkipSpaces(p) )     return 4;
    }
    return Prs_ManErrorSet(p, "Cannot find \";\" in the module definition.", 4);
}
static inline int Prs_ManReadDesign( Prs_Man_t * p )
{
    while ( 1 )
    {
        int RetValue = Prs_ManReadModule( p );
        if ( RetValue == 0 ) // end of file
            break;
        if ( RetValue == 1 ) // successfully parsed
            continue;
        if ( RetValue == 2 ) // recognized as primitive
            continue;
        if ( RetValue == 3 ) // failed and skipped
            continue;
        if ( RetValue == 4 ) // error
            return 0;
        assert( 0 );
    }
    return 1;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Prs_ManPrintModules( Prs_Man_t * p )
{
    char * pName; int i; 
    printf( "Succeeded parsing %d models:\n", Vec_IntSize(&p->vSucceeded) );
    Prs_ManForEachNameVec( &p->vSucceeded, p, pName, i )
        printf( " %s", pName );
    printf( "\n" );
    printf( "Skipped %d known models:\n", Vec_IntSize(&p->vKnown) );
    Prs_ManForEachNameVec( &p->vKnown, p, pName, i )
        printf( " %s", pName );
    printf( "\n" );
    printf( "Skipped %d failed models:\n", Vec_IntSize(&p->vFailed) );
    Prs_ManForEachNameVec( &p->vFailed, p, pName, i )
        printf( " %s", pName );
    printf( "\n" );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Ptr_t * Prs_ManReadVerilog( char * pFileName )
{
    Vec_Ptr_t * vPrs = NULL;
    Prs_Man_t * p = Prs_ManAlloc( pFileName );
    if ( p == NULL )
        return NULL;
    Prs_NtkAddVerilogDirectives( p );
    Prs_ManReadDesign( p );
    //Prs_ManPrintModules( p );
    if ( Prs_ManErrorPrint(p) )
        ABC_SWAP( Vec_Ptr_t *, vPrs, p->vNtks );
    Prs_ManFree( p );
    return vPrs;
}

void Prs_ManReadVerilogTest( char * pFileName )
{
    abctime clk = Abc_Clock();
    extern void Prs_ManWriteVerilog( char * pFileName, Vec_Ptr_t * p );
    Vec_Ptr_t * vPrs = Prs_ManReadVerilog( "c/hie/dump/1/netlist_1.v" );
//    Vec_Ptr_t * vPrs = Prs_ManReadVerilog( "aga/me/me_wide.v" );
//    Vec_Ptr_t * vPrs = Prs_ManReadVerilog( "aga/ray/ray_wide.v" );
    if ( !vPrs ) return;
    printf( "Finished reading %d networks. ", Vec_PtrSize(vPrs) );
    printf( "NameIDs = %d. ", Abc_NamObjNumMax(Prs_ManRoot(vPrs)->pStrs) );
    printf( "Memory = %.2f MB. ", 1.0*Prs_ManMemory(vPrs)/(1<<20) );
    Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
    Prs_ManWriteVerilog( "c/hie/dump/1/netlist_1_out_new.v", vPrs );
//    Prs_ManWriteVerilog( "aga/me/me_wide_out.v", vPrs );
//    Prs_ManWriteVerilog( "aga/ray/ray_wide_out.v", vPrs );
//    Abc_NamPrint( p->pStrs );
    Prs_ManVecFree( vPrs );
}


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


ABC_NAMESPACE_IMPL_END

