On 1/30/08, Clifford Heath <no / spam.please.net> wrote:
> Phil Tomson wrote:
> > What do you think would be involved to create this framework for
> > multiple output langauages? Any design docs?
>
> No design docs, but the Ruby text is built using a Ruby builder,
> which makes it sound fine and ready to go... except that the API
> to the builder allows arbitrary text strings to be appended, and
> the API assumes modules and extend() etc... Basically the builder
> API needs to be cleaned up to encapsulate the semantics and to not
> assume Ruby. Then when doing the first *other* language, cleaned
> up some more to catch the things you missed the first time. :-)
>
Yeah, I noticed the Builder stuff. I did some changes
(experimentally) to my local version of TreeTop to add an
on_success_callback that gets called when a rule parses
successfully... turns out I didn't need that functionality just now,
but it did get me familiar with some of the inards.
Thinking out loud here... So let's aay somebody did a C++ backend. As
has been mentioned, the current builder makes use of Ruby's extend
functionality quite heavily - modules get built for each alternative
and then get mixed in as needed. To get the functionality in C++ I
suppose you could just build new classes for each rule alternative.
For example the following snippet from tt:
module TopLevelSav1
def get_ports
puts "unknown ports"
end
def port_decl?
false
end
def entity_decl?
puts "Not an entity decl!"
false
end
end
def _nt_top_level_sav
start_index = index
cached = node_cache[:top_level_sav][index]
if cached
@index = cached.interval.end
return cached
end
i0, nr0 = index, []
r1 = _nt_entity_decl
r1.extend(TopLevelSav0)
nr0 << r1
if r1.success?
r0 = r1
r1.update_nested_results(nr0)
else
s2, nr2, i2 = [], [], index
loop do
r3 = parse_anything(SyntaxNode)
nr2 << r3
if r3.success?
s2 << r3
else
break
end
end
r2 = AnyNode.new(input, i2...index, s2, nr2)
r2.extend(TopLevelSav1)
....
The second extend there seems fairly straighforward: when you generate
the AnyNode class, generate a subclass that includes the methods
defined in TopLevelSav1. The first extend seems a bit more
problematic. We get a SyntaxNode object back from the
_nt_entity_decl. We could define a class TopLevelSav0 that includes
the methods defined in that module and then pass the SyntaxNode in and
construct it like so:
class TopLevelSav1 : public SyntaxNode {
public:
vector< Port* > getports();
bool port_decl();
bool entity_decl();
TopLevelSav1(SyntaxNode* sn);
}
... later:
SytaxNode* r1;
...
r1 = _nt_entity_decl();
r1 = new TopLevelSav1(r1);
Or maybe better yet:
r1 = dynamic_cast<TopLevelSav1*>(_nt_entity_decl());
Thoughts?
Oh, BTW: right now we allow Ruby code in rules:
rule foo
'something' {
def got_something?
true
end
}
end
How would we go about this for other languages?
rule foo
'something' {
#C++ code:
bool got_something() { return true; } // but how would you
handle scoping here?
}
end
It seems to me that I'd like to prototype the grammar in Ruby and then
transfer it over to C++ (or ObjC ) later on after I'm sure everything
is working. How could we make this multi-language targetting easier?
Phil