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

(constructor)constructs the generator (default-only)
(destructor)destroys the generator (virtual)

Required overrides (pure virtual)

getStreamreturns the output stream the subclass writes to
getIndentorreturns the Indentation the subclass owns
generateentry point; performs the emission
openNamespaceScopepush a name and emit the language-specific opener
closeNamespaceScopepop a name and emit the language-specific closer
getNamespacePathjoin the namespace stack into a language-appropriate path

Filename and header-guard helpers

generateFilenamebuild UpperCamelBase + .lowerext
generateHeaderGuardcompose an all-caps NS_HEADER_HH identifier from the namespace path and a header name

Case conversion

convertLowerCaseASCII lower-case
convertUpperCaseASCII upper-case
convertUpperCaseCamelUpperCamelCase from snake_or space_separated
convertLowerCaseCamellowerCamelCase from snake_or space_separated

Identifier sanitisation

replaceNonAlphanumsnon-alphanumerics replaced by a chosen character
removeNonAlphanumsnon-alphanumerics dropped

C++ string literal encoding

encodeCppString(static) encode a string as its C++ literal body would appear between double quotes

Protected data members

MemberTypeDescription
namespaceNameContainerstd::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