From: Eric Mahurin Date: 2005-05-19T05:10:16+09:00 Subject: Re: Please help with my string parser You can try the following too. It has general purpose use like yacc/lex (and ruby equivalent) and antlr, but you specify syntax in Ruby (like your class does). http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/138450 I'm still working on it. Eric --- Andreas Habel wrote: > Hi, > > I`ve written a short class for parsing and interpreting > simple 'command > strings'. I`m thinking about commands used in email based > role playing > games like Eressea (if someone knows) > > Maybe the commands could look like this > > ------------------------------------------------------------------- > code = < BEGIN > NAME="myName" > VALUE = "noValue" > END > EOF > ------------------------------------------------------------------- > > My class now parses this code and in the same action it has > to extract > the values. > > ------------------------------------------------------------------- > class Literal > > attr_reader :expr > attr_accessor :childs, :code > > def initialize( expr, code = Proc.new{} ) > @expr, @code = expr, code > @childs = [] > yield self if block_given? > end > > def <<( child ) > @childs << child > end > > def exec( str ) > res = @expr.match( str ) > @code.call( res ) > return if @childs.size <= 0 > found = false > @childs.each do |chld| > if chld.expr.match( res.post_match ) > found = true > chld.exec( res.post_match ) > break > end > end > raise "Error in Code:\n#{res.post_match.split("\n")[0]}" > unless found > end > > end > ------------------------------------------------------------------- > > Now I need to define the grammar of my language like this > (sorry for > awful linebreaks): > > ------------------------------------------------------------------- > syntax['root'] = Literal.new( //, Proc.new{|*i|}) > syntax['begin'] = Literal.new( /\A\s*BEGIN\s/i, Proc.new{|m| > p "found > BEGIN" } ) do |me| > syntax['root'] << me > end > > syntax['name'] = Literal.new( > /\A\s*NAME\s*=\s*"([a-zA-Z]*)"\s/i, > Proc.new{|m| p "found NAME with value #{m[1]}" } ) do |me| > syntax['begin'] << me > end > > syntax['value'] = Literal.new( > /\A\s*VALUE\s*=\s*"([a-zA-Z]*)"\s/i, > Proc.new{|m| p "found VALUE with value #{m[1]}" } ) do |me| > syntax['begin'] << me > syntax['name'] << me > me << syntax['name'] > end > > syntax['end'] = Literal.new( /\A\s*END/i, Proc.new{|m| p > "found END" } ) > do |me| > syntax['begin'] << me > syntax['name'] << me > syntax['value'] << me > end > > ------------------------------------------------------------------- > > And at least the parsing starts with > > ------------------------------------------------------------------- > p syntax['root'].exec( code ) > ------------------------------------------------------------------- > > It produces something like > "found BEGIN" > "found NAME with value myName" > "found VALUE with value noValue" > "found END" > > on success, and > > "found BEGIN" > syntax.rb:37:in `exec': Error in Code: (RuntimeError) > WronName="myName" from syntax.rb:33:in `exec' > from syntax.rb:30:in `each' > from syntax.rb:30:in `exec' > from syntax.rb:64 > > on failure. > > So far so good *g*. > This was my first try and I`m not sure if this is roughly the > ruby way. > I think this gets very complicated with complex commands, so > feel free > to annotate! > > Thanks, > Andreas > > __________________________________ Yahoo! Mail Mobile Take Yahoo! Mail with you! Check email on your mobile phone. http://mobile.yahoo.com/learn/mail