From: Phil Tomson Date: 2008-01-29T03:53:49+09:00 Subject: Re: Treetop parser (or PEG in general?) questions On 1/28/08, Clifford Heath 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 { 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 { 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