Next: , Previous: , Up: Project Layout   [Contents][Index]

3.2.4 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 chose to register the errors in an object, and have the library functions return this register: it is up to 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 stream to output error messages. It also keeps the current exit status until it 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:

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

Then the task system fetches the local error handler, and merges it into the global error handler 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.

  // bind::bind returns the local error handler.
  error << ::bind::bind(*ast::tasks::the_program);
File: escape.* (lib/misc/)

This file implements a means to output string while escaping non printable characters. An example:

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

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

File: flex-lexer.hh (lib/misc/)

The skeleton of the C++ scanner. Adapted from Flex’s FlexLexer.h and used as a replacement, thanks to flex++ (see

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.

File: indent.* (lib/misc/)

Exploiting regular std::ostream to produce indented output.

File: ref.* (lib/misc/)

Smart pointers implementing reference counting.

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 to 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)

Associate value to key in the current scope.

Data: get (const Key& key) const

If key was associated to some Data in the open scopes, return the most recent insertion. Otherwise, if Data is a pointer type, then return the empty pointer, else throw a std::range_error. To implement this feature, see <type_traits>

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. See the lecture notes, scanner.pdf. misc::symbol is based on misc::unique.

File: timer.* (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.

File: variant.* (lib/misc/)

A wrapper over std::variant supporting conversion operators.

Next: , Previous: , Up: Project Layout   [Contents][Index]