On 1/28/08, Clifford Heath <no / spam.please.net> wrote:

> Note that you can have a code block on each alternative as well as the
> rule as a whole:
>
> rule inline_atom
>     ( numz / wrrd { def bar; ... end } ) { def foo; ... end}
> end
>
> This adds the method foo to whichever alternative was taken, but the
> method bar only if wrrd was taken. In both cases, the methods are
> defined in a module that is extended into the node; no additional
> nodes are created by this rule.
>

This is good to know.  So you could also do this, correct?:

  rule inline_atom
    ( numz { def bar; ... end} / wrrd { def bar; ... end} ) { def foo; ... end}
  end

so that each alternative gets it's own bar method.

Here's something I'm trying to figure out.  I want to parse certain
types of declarations in a language - port declarations in VHDL.  I
don't want to have to create a parser for the whole VHDL language.  So
let's say I have this VHDL code:

  library IEEE;
  use IEEE.std_logic_1164.all;

  entity foo is
    port( a,b : in bit;
           c    : out bit;
         )
  end foo;
  other stuff blah blah...;

The only thing I care about is that port declaration in the middle.  I
want to extract the signals names from it (a,b,c) and the directions
(in,out).

I thought this might work:

grammar VHDL
    rule top_level
    ( port_decl   / .   )* {

      def get_ports
        if( elements[0].respond_to? :ports )
          elements[0].ports if elements[0].respond_to? :ports
        else
          []
        end
      end

    rule port_decl
      spc port_keyword spc '(' spc io_ports:interface_list ')' spc ';'
spc <PortDeclNode> {
      def ports
        io_ports.ports
      end
   }

  rule interface_list
    psd:interface_signal_decl more_port_signal_decls:( spc ';' spc
sig_decl:interface_signal_decl spc )*  {

      def ports
        ([psd.port_decls] + more_port_signal_decls).flatten
      end

      def more_port_signal_decls
        super.elements.map { |elt| elt.sig_decl.port_decls }
      end
    }

  end


  rule interface_signal_decl
    p_name:name more_names:(spc ',' spc other_name:name )* spc ':' spc
dir:mode spc sig_typ:sig_type spc <PortSigDeclNode> {

      class InterfaceSigDecl
        attr_accessor :name, :mode, :type
        def initialize name, mode, type
          @name = name
          @mode = mode
          @type = type
          puts "name: #{name} mode: #{mode} type: #{type}"
        end

        def to_s
          "#{@name} : #{@mode} #{@type} \n"
        end
      end

      def port_name
        p_name.text_value.downcase
      end

      def port_decls
        port_names.map {|pn| InterfaceSigDecl.new pn, direction, type }
      end

      def port_names
        [p_name.text_value.downcase] + more_names
      end

      def more_names
        super.elements.map {|elt| elt.other_name.text_value.downcase}
      end

      def direction
        dir.text_value.downcase
      end

      def type
        sig_typ.text_value.downcase
      end


    }
  end

... end grammar   (lots of other stuff, but not important for the example)

I can pass a port declaration on it's own followed by garbage, like:

  ports = parse 'port(  x : in bit  ) ; dfe;'
  ps = ports.get_ports

And that will work, I get the ports list out.

However, if I try:

    ports = parse 'xyz; port(  x : in bit  ) ; dfe;'
    ps = ports.get_ports

The ports list is empty because the '.' matches the whole string due
to the "xyz;" at the beginning of the line.

So how would one go about extracting one valid syntactic element (the
port_decl in this case) from surrounding elements that one doesn't
care about?

Phil