Defined in header <cparse/Generator.hh>
class Generator;
Generator is an abstract base for tools that emit code. Independent of the parsing side of cparse — a Generator subclass never needs a Cursor or a Parser, and vice versa. What Generator provides is the small collection of utilities every code emitter otherwise reinvents: case conversion (snake to camel and back), header-guard generation, identifier sanitisation, C++ string-literal encoding, and a namespace-scope stack.
The subclass provides three things: an output stream, an indentor, and the generate() implementation itself. Everything else is either inherited or overridable-but-usually-not.
Copy and move are deleted.
Member functions
Construction / destruction
Required overrides (pure virtual)
Filename and header-guard helpers
Case conversion
Identifier sanitisation
C++ string literal encoding
| |
| encodeCppString | (static) encode a string as its C++ literal body would appear between double quotes |
Protected data members
| Member | Type | Description |
namespaceNameContainer | std::vector<std::string> | The namespace-scope stack. Subclasses push in openNamespaceScope, pop in closeNamespaceScope, and read to build getNamespacePath. Named without the _ suffix by convention. |
Notes
What Generator does not provide
- No file management. The subclass opens the output stream.
- No error handling.
generate() returns void; the subclass decides what to do on failure.
- No template engine. Generator is a byte-by-byte code emitter, not a text templater. Produce your output character by character (or line by line via
<<).
- No language-specific emission. The namespace-scope trio is pure virtual precisely because "namespace" means different things in different targets —
namespace X {…} for C++, module X for some others, / for filesystem-style guards.
If you find yourself wanting all of these, you probably want a full templating library on top of Generator, not Generator itself.
The namespace stack pattern
Subclasses drive namespaceNameContainer in the pure-virtual trio. A representative C++-emitting subclass:
void MyGen::openNamespaceScope() noexcept {
auto const& name = /* current name from your grammar */;
namespaceNameContainer.push_back(name);
getStream() << getIndentor() << "namespace " << name << "\n"
<< getIndentor() << "{\n";
getIndentor().right();
}
void MyGen::closeNamespaceScope() noexcept {
getIndentor().left();
getStream() << getIndentor() << "} // namespace "
<< namespaceNameContainer.back() << "\n";
namespaceNameContainer.pop_back();
}
std::string MyGen::getNamespacePath() const noexcept {
std::string path;
for (auto const& n : namespaceNameContainer) {
if (!path.empty()) path += "::";
path += n;
}
return path;
}
See also