Difference between revisions of "How to parse a string"
From Verific Design Automation FAQ
| Line 37: | Line 37: | ||
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 | + | Below is a C++ code example of using string parsing (veri_file::AnalyzeModuleItem()) to add a module to the parsetree. |
<nowiki> | <nowiki> | ||
Revision as of 12: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 ;
}