Boost logo

Boost Users :

Subject: Re: [Boost-users] [boost-users][[proto] : Seeking advice on a DSL
From: Eric Niebler (eric_at_[hidden])
Date: 2010-03-17 22:06:03


On 3/18/2010 12:12 PM, Manjunath Kudlur wrote:
> Hello,
>
> I want to create a DSL where users are allowed to create "free"
> variables and then use them are parameters and local variables in
> their mini-program. For example, I want to have something like
>
> int_ a,b,c;

Trouble. These all have the same type.

> Program(&a,b) [c = b*2, a = c]
>
> The parameter with the '&' prefix represents output, the ones without
> represent input. So, Program(&a, b)[...] should behave as a function
> object with prototype void foo(int&, const int), and I should be able
> to do the following :
>
> int ra;
> BOOST_AUTO(pr, Program(&a,b) [c = b*2, a = c]);
> pr(ra, 4);
>
> I am seeking some advice on implementing the "evaluator" for this
> language. In particular, where do I store the values corresponding to
> these free variables? To draw parallels with Boost.Phoenix, in
> phoenix, arg1, arg2.. etc are uniquely typed, and the evaluator just
> creates a fusion::vector<...> with the values passed in, and argN
> evaluation just returns fusion::at_c<N>(env.args()). In my case, I
> could create a unique ID for each free variable, and create a std::map
> from ID to value, and use that as the environment. Evaluator of the
> free variables can then look up that map to find values.

Tricky. I can imagine a scheme where, as you build the program
expression, you walk the expression and keep a map<void*,int> from
parameters addresses (e.g. int_*) to monotonically increasing slot
numbers; as you go, you can replace the parameters with their slot
numbers. You end up with a program where each "a" is replaced with
"slot(0)", each "b" with "slot(2)" and each "c" with "slot(3)" (where
"slot" is some type that wraps a runtime int). Later, when evaluating
the program, the parameters to the program are put in a std::vector, and
the evaluator knows to evaluate "slot" terminals by indexing into the
vector. Handling out parameters requires special handling, as would
handling expressions where not all parameters have the same type.

This is essentially the same as what you describe above, except the
expensive mapping is done by the code the builds the program rather than
the code that evaluates it.

If you're not wedded to the use of BOOST_AUTO, you could do the mapping
during a single tree traversal when you assign the program to, say, a
boost::function with the right signature.

> But I
> consider this too heavy weight. In contrast, the fusion::vector<...>
> would incur very little overhead during run time. I will be grateful
> for any suggestions on other ways to implement the evaluator.

Hope the above gets you moving in the right direction,

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net