views:

96

answers:

3

I am developing an interpreter of a simple programming language.

  1. There are tree-structured dynamic data, where each of the data nodes has an associated (owned) type-object.
  2. There are several kinds of the types - ListType, StructType etc. - and one special - TypeRef. The TypeRef holds a name (a string) which refers to some concrete type.
  3. There is a (nearly) global map (dictionary) - I call it the environment - (std::map<string, Type*>) that translates type-names into type-objects.

The problem is, that there might be several programs loaded and each of them might have different types associated with the same names. This single assumption makes it impossible to have one global (static) environment, which would otherwise be a perfect solution.

Therefore, it seems that I need either (#1) a pointer to an environment in each type-object or (#2) to perform every operation in the context of the environment (e.g. by providing it everywhere as the first argument).

The problems I see:
(#1) Information redundancy, because all connected data nodes would have the same environment. Environments would only be different for strictly separate data.
(#2) A lot of trivial passing of the environment to subroutines, obfuscating the code.

It seems to me that this problem matches a general pattern I would call nearly static data. Any ideas what would be the best solution?

+1  A: 

What separates the environments? If it is the execution context (objects in a context only call ones in the same context), then you might use one thread per environment and store the "local-globals" in a thread-local storage (or just a global map with keys being thread IDs).

This has some disadvantages. For one, it doesn't work if there are cross-context calls. And of course it forces you into a threaded model.

Rafał Dowgird
Thanks, this is an interesting idea. But unfortunately not for my application, which must work on PC as well as on various embedded platforms.
Michal Czardybon
A: 

You might want to have two type storages - one global for concrete types, one local for TypeRefs. Local storage should be put into context of a program currently being parsed.

Basilevs
A: 

The idea of using thread-local storage is interesting, but I have finally end up with another solution:

I use the types in two phases: first they are all created and then they are "compiled". Compilation requires an environment, but is performed only once. It consist in translating all type-names into proper type-objects. After the compilation the environment is no longer needed.

Nevertheless, I think it is still more a workaround than a general solution.

Michal Czardybon