Difference between revisions of "How to parse a string"
From Verific Design Automation FAQ
(6 intermediate revisions by the same user not shown) | |||
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:: | + | :- 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) { | ||
− | + | 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 ; }