Difference between revisions of "How to parse a string"

From Verific Design Automation FAQ
Jump to: navigation, search
(Created page with "Let's say you want to add a node to the parsetree. One of the simple ways to do so is to start with a text string; then "parse" that string to get a VHDL or Verilog construct...")
 
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Let's say you want to add a node to the parsetree.
+
Let's say you want to add a node to the parse tree.
  
One of the simple ways to do so is to start with a text string; then "parse" that string to get a VHDL or Verilog construct. The construct then can be added to the parsetree.
+
One simple way to do so is to start with a text string, then "parse" that string to get a VHDL or Verilog construct. The construct can then be added to the parse tree.
  
 
Below are the APIs to parse a string:
 
Below are the APIs to parse a string:
Line 9: Line 9:
 
* VeriModuleItem *veri_file::AnalyzeModuleItem(const char *module_item, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0, VeriScope *container_scope = 0)
 
* VeriModuleItem *veri_file::AnalyzeModuleItem(const char *module_item, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0, VeriScope *container_scope = 0)
 
* VeriStatement *veri_file::AnalyzeStatement(const char *statement, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0, VeriScope *container_scope = 0)
 
* VeriStatement *veri_file::AnalyzeStatement(const char *statement, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0, VeriScope *container_scope = 0)
Appropriate scope information where the given string is valid should be passed to the APIs to have them work properly.
+
Notes for Verilog :
Need to call Resolve() on the returned parse tree nodes with proper scope where these items will be used.
+
:- appropriate scope information where the given string is valid should be passed to the APIs for them to work properly
VeriTreeNode::VERI_UPWARD_SCOPE_NAME can be passed as the resolve environment.
+
:- need to call Resolve() on the returned parse tree nodes with proper scope where these items will be used
If required, they can be added to the existing parse tree using the appropriate APIs.
+
:- VeriTreeNode::VERI_UNDEF_ENV can be passed as the Resolve() environment
 +
:- if required the nodes can be added to the existing parse tree using the appropriate APIs
  
 
'''VHDL:'''
 
'''VHDL:'''
Line 19: Line 20:
 
* VhdlStatement *vhdl_file::AnalyzeConcurrentStatement(const char *statement, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0, VhdlScope *container_scope = 0)
 
* VhdlStatement *vhdl_file::AnalyzeConcurrentStatement(const char *statement, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0, VhdlScope *container_scope = 0)
 
* VhdlDesignUnit *vhdl_file::AnalyzeUnit(const char *unit, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0)
 
* VhdlDesignUnit *vhdl_file::AnalyzeUnit(const char *unit, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0)
Appropriate scope information where the given string is valid should be passed to the APIs to have them work properly.
+
Notes for VHDL :
We need vhdl_file::AnalyzeSequentialStatement() as well as vhdl_file::AnalyzeConcurrentStatement() to differentiate the starting point between the two.
+
:- appropriate scope information where the given string is valid should be passed to the APIs for them to work properly
Verilog AnalyzeModuleItem() = VHDL AnalyzeConcurrentStatement() and AnalyzeUnit() both
+
:- need vhdl_file::AnalyzeSequentialStatement() as well as vhdl_file::AnalyzeConcurrentStatement() to differentiate between the starting points of the two
Verilog AnalyzeStatement() = VHDL AnalyzeSequentialStatement()
+
:- Verilog AnalyzeModuleItem() = both VHDL AnalyzeConcurrentStatement() and VHDL AnalyzeUnit()
 +
:- Verilog AnalyzeStatement() = VHDL AnalyzeSequentialStatement()
  
 +
An example excerpt of C++ code using AnalyzeExpr() is as follows :
 +
    VeriExpression *expr = veri_file::AnalyzeExpr(expr_string, veri_file::SYSTEM_VERILOG);
 +
    VeriScope *current_scope = module->GetScope() ;
 +
    if (expr) {
 +
        expr->Resolve(current_scope, VeriTreeNode::VERI_UNDEF_ENV);
 +
        // plus anything else user may want to add
 +
    }
  
Off-course full designs can be analyzed from strings. Please use streams for that.
+
Full designs can be analyzed from strings as well. Please use streams for that.
 
See [https://www.verific.com/docs/index.php?title=Analyzing_Stream_Inputs Analyzing Stream Inputs]
 
See [https://www.verific.com/docs/index.php?title=Analyzing_Stream_Inputs Analyzing Stream Inputs]
 +
 +
Below is a C++ code example of using string parsing (veri_file::AnalyzeModuleItem()) to add a module to the parsetree.
 +
 +
<nowiki>
 +
#include <iostream>
 +
 +
#include "veri_file.h"
 +
#include "VeriModule.h"
 +
#include "VeriId.h"
 +
#include "VeriScope.h"
 +
#include "VeriLibrary.h"
 +
#include "DataBase.h"
 +
#include "VeriWrite.h"
 +
 +
#include "Array.h"
 +
 +
#ifdef VERIFIC_NAMESPACE
 +
using namespace Verific ;
 +
#endif
 +
 +
int main(void)
 +
{
 +
    // Analyze the file:
 +
    Array files(1) ;
 +
    files.InsertLast("test.v") ;
 +
    if (!veri_file::AnalyzeMultipleFiles(&files, veri_file::SYSTEM_VERILOG, "work")) return 1 ;
 +
 +
    // Get the 'top' module:
 +
    VeriModule *top = veri_file::GetModule("test") ;
 +
    if (!top) return 2 ;
 +
 +
    // Get the library of the 'top' module:
 +
    VeriLibrary *work_lib = top->GetLibrary() ;
 +
    if (!work_lib) return 4 ;
 +
 +
    // Get the compilation unit of the 'top' module and then the compilation unit scope where the class is declared:
 +
    VeriModule *root = top->GetCompilationUnit() ;
 +
    VeriScope *scope = (root) ? root->GetScope() : 0 ;
 +
 +
    // Analyze a new module under the scope of the compilation unit:
 +
    linefile_type dummy_lf = LineFile::EncodeLineFile("read-from-string", 1) ;
 +
    VeriModuleItem *mi = veri_file::AnalyzeRootItem("module new_module ( RESET, SET, CLK, IN, O );parameter INIT = 1'b0;input RESET;input SET;input CLK;input IN;output reg O = INIT;endmodule", veri_file::SYSTEM_VERILOG, dummy_lf, scope) ;
 +
    if (!mi) return 5 ;
 +
 +
    // Get the identifier of the module item:
 +
    VeriIdDef *id = mi->GetId() ;
 +
    if (!id) return 6 ;
 +
 +
    // Get the VeriModule * from the identifier of the module:
 +
    // This will return NULL if it is not actually a module.
 +
    VeriModule *mod = id->GetModule() ;
 +
    if (!mod) return 7 ;
 +
 +
    // Add to user defined library:
 +
    VeriLibrary *user_define_lib = veri_file::GetLibrary("new_lib", 1 /* create if needed */) ;
 +
    VERIFIC_ASSERT(user_define_lib) ; // Must be there, should be created if it was not there
 +
    if (!user_define_lib->AddModule(mod)) return 8 ;
 +
 +
    mod->Resolve(scope, VeriTreeNode::VERI_UNDEF_ENV) ;
 +
 +
    veri_file::PrettyPrint("pp.v.golden.new", 0) ;
 +
 +
    // Finally, elaborate the top module:
 +
    veri_file::AddLOption("user_define_lib") ;
 +
    if (!veri_file::Elaborate("test")) return 9 ;
 +
 +
    Netlist *top_nl = Netlist::PresentDesign() ;
 +
    if (!top_nl) return 10 ;
 +
 +
    VeriWrite vw ;
 +
    vw.WriteFile ("netlist_out.v.golden.new", top_nl) ;
 +
 +
    return 0 ;
 +
}
 +
</nowiki>

Latest revision as of 09:10, 18 June 2024

Let's say you want to add a node to the parse tree.

One simple way to do so is to start with a text string, then "parse" that string to get a VHDL or Verilog construct. The construct can then be added to the parse tree.

Below are the APIs to parse a string:

Verilog:

  • VeriExpression *veri_file::AnalyzeExpr(const char *expr, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0)
  • VeriModuleItem *veri_file::AnalyzeModuleItem(const char *module_item, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0, VeriScope *container_scope = 0)
  • VeriStatement *veri_file::AnalyzeStatement(const char *statement, unsigned verilog_mode=VERILOG_2K, const linefile_type line_file = 0, VeriScope *container_scope = 0)

Notes for Verilog :

- appropriate scope information where the given string is valid should be passed to the APIs for them to work properly
- need to call Resolve() on the returned parse tree nodes with proper scope where these items will be used
- VeriTreeNode::VERI_UNDEF_ENV can be passed as the Resolve() environment
- if required the nodes can be added to the existing parse tree using the appropriate APIs

VHDL:

  • VhdlExpression *vhdl_file::AnalyzeExpr(const char *expr, unsigned vhdl_mode=VHDL_93, const linefile_type line_file=0)
  • VhdlStatement *vhdl_file::AnalyzeSequentialStatement(const char *statement, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0, * VhdlScope *container_scope = 0)
  • VhdlStatement *vhdl_file::AnalyzeConcurrentStatement(const char *statement, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0, VhdlScope *container_scope = 0)
  • VhdlDesignUnit *vhdl_file::AnalyzeUnit(const char *unit, unsigned vhdl_mode = VHDL_93, const char *lib_name = "work", const linefile_type line_file = 0)

Notes for VHDL :

- appropriate scope information where the given string is valid should be passed to the APIs for them to work properly
- need vhdl_file::AnalyzeSequentialStatement() as well as vhdl_file::AnalyzeConcurrentStatement() to differentiate between the starting points of the two
- Verilog AnalyzeModuleItem() = both VHDL AnalyzeConcurrentStatement() and VHDL AnalyzeUnit()
- Verilog AnalyzeStatement() = VHDL AnalyzeSequentialStatement()

An example excerpt of C++ code using AnalyzeExpr() is as follows :

   VeriExpression *expr = veri_file::AnalyzeExpr(expr_string, veri_file::SYSTEM_VERILOG);
   VeriScope *current_scope = module->GetScope() ;
   if (expr) {
       expr->Resolve(current_scope, VeriTreeNode::VERI_UNDEF_ENV);
       // plus anything else user may want to add
   }

Full designs can be analyzed from strings as well. Please use streams for that. See Analyzing Stream Inputs

Below is a C++ code example of using string parsing (veri_file::AnalyzeModuleItem()) to add a module to the parsetree.

#include <iostream>

#include "veri_file.h"
#include "VeriModule.h"
#include "VeriId.h"
#include "VeriScope.h"
#include "VeriLibrary.h"
#include "DataBase.h"
#include "VeriWrite.h"

#include "Array.h"

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

int main(void)
{
    // Analyze the file:
    Array files(1) ;
    files.InsertLast("test.v") ;
    if (!veri_file::AnalyzeMultipleFiles(&files, veri_file::SYSTEM_VERILOG, "work")) return 1 ;

    // Get the 'top' module:
    VeriModule *top = veri_file::GetModule("test") ;
    if (!top) return 2 ;

    // Get the library of the 'top' module:
    VeriLibrary *work_lib = top->GetLibrary() ;
    if (!work_lib) return 4 ;

    // Get the compilation unit of the 'top' module and then the compilation unit scope where the class is declared:
    VeriModule *root = top->GetCompilationUnit() ;
    VeriScope *scope = (root) ? root->GetScope() : 0 ;

    // Analyze a new module under the scope of the compilation unit:
    linefile_type dummy_lf = LineFile::EncodeLineFile("read-from-string", 1) ;
    VeriModuleItem *mi = veri_file::AnalyzeRootItem("module new_module ( RESET, SET, CLK, IN, O );parameter INIT = 1'b0;input RESET;input SET;input CLK;input IN;output reg O = INIT;endmodule", veri_file::SYSTEM_VERILOG, dummy_lf, scope) ;
    if (!mi) return 5 ;

    // Get the identifier of the module item:
    VeriIdDef *id = mi->GetId() ;
    if (!id) return 6 ;

    // Get the VeriModule * from the identifier of the module:
    // This will return NULL if it is not actually a module.
    VeriModule *mod = id->GetModule() ;
    if (!mod) return 7 ;

    // Add to user defined library:
    VeriLibrary *user_define_lib = veri_file::GetLibrary("new_lib", 1 /* create if needed */) ;
    VERIFIC_ASSERT(user_define_lib) ; // Must be there, should be created if it was not there
    if (!user_define_lib->AddModule(mod)) return 8 ;

    mod->Resolve(scope, VeriTreeNode::VERI_UNDEF_ENV) ;

    veri_file::PrettyPrint("pp.v.golden.new", 0) ;

    // Finally, elaborate the top module:
    veri_file::AddLOption("user_define_lib") ;
    if (!veri_file::Elaborate("test")) return 9 ;

    Netlist *top_nl = Netlist::PresentDesign() ;
    if (!top_nl) return 10 ;

    VeriWrite vw ;
    vw.WriteFile ("netlist_out.v.golden.new", top_nl) ;

    return 0 ;
}