A
Andreas Habel
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 = <<EOF
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
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 = <<EOF
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