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...")
 
(4 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_UPWARD_SCOPE_NAME 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) {
 +
        myexp->Resolve(current_scope, VeriTreeNode::VERI_UPWARD_SCOPE_NAME);
 +
        // 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 "Array.h"
 +
 +
#ifdef VERIFIC_NAMESPACE
 +
using namespace Verific ;
 +
#endif
 +
 +
int main(void)
 +
{
 +
    // Analyze the file:
 +
    Array files(1) ;
 +
    files.InsertLast("test.sv") ;
 +
    if (!veri_file::AnalyzeMultipleFiles(&files, veri_file::SYSTEM_VERILOG, "work")) return 1 ;
 +
 +
    // Get the 'top' module:
 +
    VeriModule *top = veri_file::GetModule("top") ;
 +
    if (!top) return 2 ;
 +
 +
    // Elaborate the 'top' module:
 +
    if (!veri_file::ElaborateStatic(top->Name())) return 3 ;
 +
 +
    // 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:
 +
    VeriModuleItem *mi = veri_file::AnalyzeModuleItem("module test_A;\n    A tests[1];\nendmodule", veri_file::SYSTEM_VERILOG, 0UL, 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 the module to the same library as the 'top' module:
 +
    if (!work_lib->AddModule(mod)) return 8 ;
 +
 +
    // Finally, elaborate the new module:
 +
    if (!veri_file::ElaborateStatic(mod->Name())) return 9 ;
 +
 +
    veri_file::PrettyPrint("test_se.v.golden.new", 0) ;
 +
 +
    return 0 ;
 +
}
 +
</nowiki>

Revision as of 13:02, 17 June 2021

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_UPWARD_SCOPE_NAME 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) {
       myexp->Resolve(current_scope, VeriTreeNode::VERI_UPWARD_SCOPE_NAME);
       // 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 "Array.h"

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

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

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

    // Elaborate the 'top' module:
    if (!veri_file::ElaborateStatic(top->Name())) return 3 ;

    // 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:
    VeriModuleItem *mi = veri_file::AnalyzeModuleItem("module test_A;\n    A tests[1];\nendmodule", veri_file::SYSTEM_VERILOG, 0UL, 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 the module to the same library as the 'top' module:
    if (!work_lib->AddModule(mod)) return 8 ;

    // Finally, elaborate the new module:
    if (!veri_file::ElaborateStatic(mod->Name())) return 9 ;

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

    return 0 ;
}