The lib/misc Directory

Convenient C++ tools.

File: contract.* (lib/misc/)

A useful improvement over cassert.

File: error.* (lib/misc/)

The class misc::error implements an error register. Because libraries are expected to be pure, they cannot issue error messages to the error output, nor exit with failure. One could pass call-backs (as functions or as objects) to set up error handling. Instead, we choose to register the errors in an object, and have the library functions return this register: it is up the caller to decide what to do with these errors. Note also that direct calls to std::exit bypass stack unwinding. In other words, with std::exit (instead of throw) your application leaks memory.

An instance of misc:error can be used as if it were a steam to output error messages. It also keeps the current exit status until is “triggered”, i.e., until it is thrown. Each module has its own error handler. For instance, the Binder has an error_ attribute, and uses it to report errors:

void
Binder::error(const ast::Ast& loc, const std::string& msg)
{
  error_ << misc::error::error_type::bind
         << loc.location_get() << ": " << msg << std::endl;
}

Then the task system fetches the local error handler, and merges it into the global error handler task_error() (see common.*). Some tasks trigger the error handler: if errors were registered, an exception is raised to exit the program cleanly. The following code demonstrates both aspects.

void
bindings_compute()
{
  // bind::bind returns the local error handler.
  task_error() << ::bind::bind(*ast::tasks::the_program);
  task_error().exit_on_error();
}

File: escape.* (lib/misc/)

The file implements a means to output string while escaping non printable characters. An exemple:

std::cout << "escape(\"\111\") = " << escape("\"\111\"") << std::endl;

Understanding how escape works is required starting from TC-2.

File: graph.* (lib/misc/)

This file contains a generic implementation of oriented and undirected graphs. Understanding how graph works is required starting from TC-8.

Graphs are implemented using the boost::Graph library.

File: indent.* (lib/misc/)

Exploiting regular std::ostream to produce indented output.

std::cout << "Not indented";
std::cout << misc::incendl << "Indented, " << misc::decindent;
std::cout << "Still indented" << misc::iendl;
std::cout << "Not indented";

will give

Not indented
    Indented, Still indented
Not indented

File: ref.* (lib/misc/)

Smart pointers implementing reference counting. This class inherits from shared_ptr and adds implicit constructors and cast methods.

This allows creating shared pointers without using std::make_shared, but with new operator.

File: set.* (lib/misc/)

A wrapper around std::set that introduce convenient operators (operator+ and so forth).

File: scoped-map.* (lib/misc/)

The handling of misc::scoped_map<Key, Data>, generic scoped map, serving as a basis for symbol tables used by the Binder. misc::scoped_map maps a Key top a Data (that should ring a bell …). You are encouraged to implement something simple, based on stacks (see std::stack, or better yet, std::vector) and maps (see std::map).

It must provide this interface:

void put(const Key& key, const Data& value)

Associated value to key in the current scope.

Data get(const Key& key) const

If key was associated to some Data in the open scoped, return the most recent insertion. Otherwise, if Data is a pointer type, then return the null pointer, else throw a std::range_error. To implement this feature, see <concepts>. Pay close attention to the Redeclarations section of that page to help declare the constrained get method.

std::ostream& dump(std::ostream& ostr) const

Send the content of this table on ostr in a human-readable manner, and return the stream.

void scope_begin()

Open a new scope.

void scope_end()

Close the last scope, forgetting everything since the latest scope_begin().

File: symbol.* (lib/misc/)

In a program, the rule for identifiers is to be used many times: at least once for its definition, and once for each use. Just think about the number of occurrences of size_t in a C program for instance.

To save space one keeps a single copy of each identifier. This provides additional benefits: the address of this single copy can be used as a key: comparisons (equality or order) are much faster.

The class misc::symbol is an implementation of this idea; misc::symbol is based on misc::unique.

File: time.* (lib/misc/)

A class that makes it possible to have timings of processes, similarly to gcc’s --time-report, or bison’s --report=time. It is used in the Task machinery, but can be used to provide better timings (e.g., separating the scanner from the parser).

File: unique.* (lib/misc/)

A generic class implementing the Flyweight design pattern; It maps identical objects to a unique reference. See refactoring.guru for more details about this design pattern.

File: variant.* (lib/misc/)

A wrapper over std::variant supporting conversion operators.

File: singleton.* (lib/misc/)

A generic class implementing the Singleton design pattern.

File: list.* (lib/misc/)

Functional-style manipulation of vectors.

File: lambda-visitor.* (lib/misc/)

Helper class for std::visit based pattern-matching with lambdas.