Internals: Enable EmitV to output formatted code to std::ostream (#6239)
Introduce V3OutStream as a V3OutFormatter that writes to a stream instead of a file. This can be used to emit formatted code fragments e.g. in debug prints and graph dumps.
This commit is contained in:
parent
2b62f5a625
commit
9d2adf3e49
|
|
@ -28,12 +28,13 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
// ######################################################################
|
||||
// Emit statements and expressions
|
||||
|
||||
class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||
class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
||||
// STATE - across all visitors
|
||||
const bool m_suppressUnknown = false;
|
||||
const bool m_alwaysTrackText; // Always track all NodeSimpleText
|
||||
const bool m_suppressUnknown; // Do not error on unknown node
|
||||
|
||||
// STATE - for current visit position (use VL_RESTORER)
|
||||
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
||||
AstSenTree* m_sensesp = nullptr; // Domain for printing one a ALWAYS under a ACTIVE
|
||||
bool m_suppressSemi = false; // Non-statement, don't print ;
|
||||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
|
||||
|
|
@ -72,7 +73,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
// VISITORS
|
||||
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
|
||||
putfs(nodep, nodep->verilogKwd() + " " + EmitCBase::prefixNameProtect(nodep) + ";\n");
|
||||
iterateChildrenConst(nodep);
|
||||
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
||||
}
|
||||
|
|
@ -461,7 +462,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
puts(";\n");
|
||||
}
|
||||
void visit(AstNodeSimpleText* nodep) override {
|
||||
if (nodep->tracking() || m_trackText) {
|
||||
if (nodep->tracking() || m_alwaysTrackText) {
|
||||
puts(nodep->text());
|
||||
} else {
|
||||
putsNoTracking(nodep->text());
|
||||
|
|
@ -965,9 +966,9 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
}
|
||||
|
||||
public:
|
||||
explicit EmitVBaseVisitorConst(bool suppressUnknown, AstSenTree* domainp)
|
||||
: m_suppressUnknown{suppressUnknown}
|
||||
, m_sensesp{domainp} {}
|
||||
explicit EmitVBaseVisitorConst(bool alwaysTrackText, bool suppressUnknown)
|
||||
: m_alwaysTrackText{alwaysTrackText}
|
||||
, m_suppressUnknown{suppressUnknown} {}
|
||||
~EmitVBaseVisitorConst() override = default;
|
||||
};
|
||||
|
||||
|
|
@ -975,18 +976,19 @@ public:
|
|||
// Emit to an output file
|
||||
|
||||
class EmitVFileVisitor final : public EmitVBaseVisitorConst {
|
||||
// STATE
|
||||
V3OutVFile& m_of; // The output file
|
||||
// METHODS
|
||||
void puts(const string& str) override { ofp()->puts(str); }
|
||||
void putbs(const string& str) override { ofp()->putbs(str); }
|
||||
void putsNoTracking(const string& str) override { m_of.putsNoTracking(str); }
|
||||
void puts(const string& str) override { m_of.puts(str); }
|
||||
void putbs(const string& str) override { m_of.putbs(str); }
|
||||
void putfs(AstNode*, const string& str) override { putbs(str); }
|
||||
void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||
void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
|
||||
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutVFile* ofp, bool trackText, bool suppressUnknown)
|
||||
: EmitVBaseVisitorConst{suppressUnknown, nullptr} {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutVFile& of, bool alwaysTrackText, bool suppressUnknown)
|
||||
: EmitVBaseVisitorConst{alwaysTrackText, suppressUnknown}
|
||||
, m_of{of} {
|
||||
iterateConst(nodep);
|
||||
}
|
||||
~EmitVFileVisitor() override = default;
|
||||
|
|
@ -996,19 +998,25 @@ public:
|
|||
// Emit to a stream (perhaps stringstream)
|
||||
|
||||
class EmitVStreamVisitor final : public EmitVBaseVisitorConst {
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
// STATE
|
||||
V3OutStream m_os; // The output stream formatter
|
||||
bool m_tracking; // Use line tracking
|
||||
// METHODS
|
||||
void putsNoTracking(const string& str) override { m_os << str; }
|
||||
void puts(const string& str) override { putsNoTracking(str); }
|
||||
void putbs(const string& str) override { puts(str); }
|
||||
void putsNoTracking(const string& str) override { m_os.putsNoTracking(str); }
|
||||
void puts(const string& str) override {
|
||||
m_tracking ? m_os.puts(str) : m_os.putsNoTracking(str);
|
||||
}
|
||||
void putbs(const string& str) override {
|
||||
m_tracking ? m_os.putbs(str) : m_os.putsNoTracking(str);
|
||||
}
|
||||
void putfs(AstNode*, const string& str) override { putbs(str); }
|
||||
void putqs(AstNode*, const string& str) override { putbs(str); }
|
||||
|
||||
public:
|
||||
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os)
|
||||
: EmitVBaseVisitorConst{false, nullptr}
|
||||
, m_os(os) { // Need () or GCC 4.8 false warning
|
||||
EmitVStreamVisitor(const AstNode* nodep, std::ostream& os, bool tracking)
|
||||
: EmitVBaseVisitorConst{false, false}
|
||||
, m_os{os, V3OutFormatter::LA_VERILOG}
|
||||
, m_tracking{tracking} {
|
||||
iterateConst(const_cast<AstNode*>(nodep));
|
||||
}
|
||||
~EmitVStreamVisitor() override = default;
|
||||
|
|
@ -1018,7 +1026,7 @@ public:
|
|||
// EmitV class functions
|
||||
|
||||
void V3EmitV::verilogForTree(const AstNode* nodep, std::ostream& os) {
|
||||
{ EmitVStreamVisitor{nodep, os}; }
|
||||
{ EmitVStreamVisitor{nodep, os, /* tracking: */ false}; }
|
||||
}
|
||||
|
||||
void V3EmitV::emitvFiles() {
|
||||
|
|
@ -1028,9 +1036,8 @@ void V3EmitV::emitvFiles() {
|
|||
AstVFile* const vfilep = VN_CAST(filep, VFile);
|
||||
if (vfilep && vfilep->tblockp()) {
|
||||
V3OutVFile of{vfilep->name()};
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated Verilog\n");
|
||||
{ EmitVFileVisitor{vfilep->tblockp(), &of, true, false}; }
|
||||
of.puts("// DESCRIPTION: Verilator generated Verilog\n");
|
||||
{ EmitVFileVisitor{vfilep->tblockp(), of, true, false}; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1038,5 +1045,5 @@ void V3EmitV::emitvFiles() {
|
|||
void V3EmitV::debugEmitV(const string& filename) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
V3OutVFile of{filename};
|
||||
{ EmitVFileVisitor{v3Global.rootp(), &of, true, true}; }
|
||||
{ EmitVFileVisitor{v3Global.rootp(), of, true, true}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -640,11 +640,10 @@ bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl)
|
|||
}
|
||||
|
||||
//######################################################################
|
||||
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
||||
// V3OutFormatter: A class for printing code with automatic indentation.
|
||||
|
||||
V3OutFormatter::V3OutFormatter(const string& filename, V3OutFormatter::Language lang)
|
||||
: m_filename{filename}
|
||||
, m_lang{lang} {
|
||||
V3OutFormatter::V3OutFormatter(V3OutFormatter::Language lang)
|
||||
: m_lang{lang} {
|
||||
m_blockIndent = v3Global.opt.decoration() ? 4 : 1;
|
||||
m_commaWidth = v3Global.opt.decoration() ? 50 : 150;
|
||||
}
|
||||
|
|
@ -962,7 +961,8 @@ void V3OutFormatter::printf(const char* fmt...) {
|
|||
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
|
||||
|
||||
V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang)
|
||||
: V3OutFormatter{filename, lang}
|
||||
: V3OutFormatter{lang}
|
||||
, m_filename{filename}
|
||||
, m_bufferp{new std::array<char, WRITE_BUFFER_SIZE_BYTES>{}} {
|
||||
if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) {
|
||||
v3fatal("Can't write file: " << filename);
|
||||
|
|
@ -992,6 +992,13 @@ void V3OutCFile::putsGuard() {
|
|||
puts("#define " + var + " // guard\n");
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3OutStream
|
||||
|
||||
V3OutStream::V3OutStream(std::ostream& ostream, V3OutFormatter::Language lang)
|
||||
: V3OutFormatter{lang}
|
||||
, m_ostream{ostream} {}
|
||||
|
||||
//######################################################################
|
||||
// VIdProtect
|
||||
|
||||
|
|
|
|||
29
src/V3File.h
29
src/V3File.h
|
|
@ -102,7 +102,7 @@ public:
|
|||
};
|
||||
|
||||
//============================================================================
|
||||
// V3OutFormatter: A class for automatic indentation of C++ or Verilog code.
|
||||
// V3OutFormatter: A class for automatic indentation of output code.
|
||||
|
||||
class V3OutFormatter VL_NOT_FINAL {
|
||||
// TYPES
|
||||
|
|
@ -113,7 +113,6 @@ public:
|
|||
|
||||
private:
|
||||
// MEMBERS
|
||||
const string m_filename;
|
||||
const Language m_lang; // Indenting Verilog code
|
||||
int m_blockIndent; // Characters per block indent
|
||||
int m_commaWidth; // Width after which to break at ,'s
|
||||
|
|
@ -132,10 +131,9 @@ private:
|
|||
void putcNoTracking(char chr);
|
||||
|
||||
public:
|
||||
V3OutFormatter(const string& filename, Language lang);
|
||||
V3OutFormatter(Language lang);
|
||||
virtual ~V3OutFormatter() = default;
|
||||
// ACCESSORS
|
||||
string filename() const { return m_filename; }
|
||||
int column() const { return m_column; }
|
||||
int blockIndent() const { return m_blockIndent; }
|
||||
void blockIndent(int flag) { m_blockIndent = flag; }
|
||||
|
|
@ -165,7 +163,7 @@ public:
|
|||
void indentInc() { m_indentLevel += m_blockIndent; }
|
||||
void indentDec() {
|
||||
m_indentLevel -= m_blockIndent;
|
||||
UASSERT(m_indentLevel >= 0, ": " << m_filename << ": Underflow of indentation");
|
||||
UASSERT(m_indentLevel >= 0, "Underflow of indentation");
|
||||
}
|
||||
void blockInc() { m_parenVec.push(m_indentLevel + m_blockIndent); }
|
||||
void blockDec() {
|
||||
|
|
@ -201,6 +199,7 @@ class V3OutFile VL_NOT_FINAL : public V3OutFormatter {
|
|||
static constexpr std::size_t WRITE_BUFFER_SIZE_BYTES = 128 * 1024;
|
||||
|
||||
// MEMBERS
|
||||
const std::string m_filename;
|
||||
FILE* m_fp = nullptr;
|
||||
std::size_t m_usedBytes = 0; // Number of bytes stored in m_bufferp
|
||||
std::size_t m_writtenBytes = 0; // Number of bytes written to output
|
||||
|
|
@ -214,6 +213,8 @@ public:
|
|||
V3OutFile& operator=(V3OutFile&&) = delete;
|
||||
~V3OutFile() override;
|
||||
|
||||
std::string filename() const { return m_filename; }
|
||||
|
||||
void putsForceIncs();
|
||||
|
||||
void statRecordWritten() {
|
||||
|
|
@ -430,6 +431,24 @@ public:
|
|||
virtual void putsHeader() { puts("<?xml version=\"1.0\" ?>\n"); }
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// V3OutStream: A class for printing formatted code to any std::ostream
|
||||
|
||||
class V3OutStream VL_NOT_FINAL : public V3OutFormatter {
|
||||
// MEMBERS
|
||||
std::ostream& m_ostream;
|
||||
|
||||
VL_UNCOPYABLE(V3OutStream);
|
||||
VL_UNMOVABLE(V3OutStream);
|
||||
|
||||
public:
|
||||
V3OutStream(std::ostream& ostream, V3OutFormatter::Language lang);
|
||||
~V3OutStream() override = default;
|
||||
|
||||
void putcOutput(char chr) override { m_ostream << chr; };
|
||||
void putsOutput(const char* str) override { m_ostream << str; };
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// VIdProtect: Hash identifier names in output files to protect them
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue