Prev: deploy issues
Next: Dia 1.1 released!
From: Lui Kore on 16 Feb 2010 04:31 # Just added another example: a Scheme interpreter. require "rsec" class Scheme include Rsec::Helpers def initialize bra = /\(\s*/.r.skip ket = /\s*\)/.r.skip boolean = /\#[tf]/. r.map {|n| ValueNode[n=='#t'] } integer = /0|[1-9]\d*/.r.map {|n| ValueNode[n.to_i] } id = /[^\s\(\)\[\]]+/.r.on {|n| def n.eval bind, *xs bind[self] end } atom = boolean | integer | id list = nil # declare for lazy cell = atom | lazy{list} list = ( bra < cell.join_(spacee) < ket ).map {|(n)| ListNode[*n] } @parser = (spacee < cell.join_(spacee) < spacee).map {|(n)| ListNode[*n] } end def run source @ctx = Rsec::ParseContext.new source, 'scm' res = @parser._parse @ctx if !res or !@ctx.eos? raise Rsec::ParseError['syntax error', @ctx] end res.eval Runtime.new end ValueNode = Struct.new :val class ValueNode def eval *xs val end def pretty_print q q.text "<#{val}>" end end class ListNode < Array def eval bind head, *tail = self case head when String pr = bind[head] pr.is_a?(Proc) ? pr[bind, tail] : pr when ListNode map{|n| n.eval bind }.last end end end class Bind < Hash def initialize parent = {} @parent = parent end def [] key super(key) || @parent[key] end # define a function def define id, &p self[id] = proc do |bind, xs| p[* xs.map{|x| x.eval bind }] end end end class Runtime < Bind def initialize super() self['define'] = proc do |bind, (param, body)| case param # (define (name plist[0]) body) when ListNode func, *xs = param self[func] = self['lambda'][bind, [xs, body]] # (define param body) when String self[param] = body.eval bind end end # declare: # (lambda (xs[0] xs[1]) body) self['lambda'] = proc do |bind_def, (xs, body)| xs = [xs] if xs.is_a?(String) new_bind = Bind.new bind_def # calling: # (some vs[0] vs[1]) proc do |bind_call, vs| vs = vs.map{|v| v.eval bind_call} new_bind.merge! Hash[xs.zip vs] body.eval new_bind end end # lazy (short cut) self['if'] = proc do |bind, (p, left, right)| p.eval(bind) ? left.eval(bind) : right.eval(bind) end # misc %w|+ - * / ** % > <|.each do |s| define s, &s.to_sym end define '=', &:== define 'display' do |x| puts x end end end end s = Scheme.new s.run File.read ARGV[0] -- Posted via http://www.ruby-forum.com/.
|
Pages: 1 Prev: deploy issues Next: Dia 1.1 released! |