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