Difference between revisions of "How to parse a string"

From Verific Design Automation FAQ
Jump to: navigation, search
 
(7 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
Let's say you want to add a node to the parse tree.
 
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 then can be added 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:
 
Below are the APIs to parse a string:
Line 12: Line 12:
 
:- appropriate scope information where the given string is valid should be passed to the APIs for them to work properly
 
:- 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
 
:- need to call Resolve() on the returned parse tree nodes with proper scope where these items will be used
:- VeriTreeNode::VERI_UPWARD_SCOPE_NAME can be passed as the Resolve() environment
+
:- 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
 
:- if required the nodes can be added to the existing parse tree using the appropriate APIs
  
Line 30: Line 30:
 
     VeriScope *current_scope = module->GetScope() ;
 
     VeriScope *current_scope = module->GetScope() ;
 
     if (expr) {
 
     if (expr) {
         myexp->Resolve(current_scope, VeriTreeNode::VERI_UPWARD_SCOPE_NAME);
+
         expr->Resolve(current_scope, VeriTreeNode::VERI_UNDEF_ENV);
 
         // plus anything else user may want to add
 
         // plus anything else user may want to add
 
     }
 
     }
Line 36: Line 36:
 
Full designs can be analyzed from strings as well. 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 ;
}