Skip to content

Instantly share code, notes, and snippets.

@podhmo
Created October 25, 2010 09:19
Show Gist options
  • Save podhmo/644657 to your computer and use it in GitHub Desktop.
Save podhmo/644657 to your computer and use it in GitHub Desktop.
require 'object'
def for_each(list)
loop do
yield(list.car)
list = list.cdr
return if list.nil?
end
end
def map(list)
[].tap do |r|
loop do
r << yield(list.car)
list = list.cdr
return r if list.nil?
end
end
end
class Evalator
def initialize env
@env = env
end
def myeval(expr)
if expr.respond_to?(:car)
fn = expr.car
args = map(expr.cdr){|e| myeval(e)}
find(fn).call(*args)
else
expr
end
end
def find(sym)
return @env[sym]
end
end
if __FILE__ == $0
e = Evalator.new({:+ => lambda{|*args| args.inject(0){|s,n| s + n}}})
Cons::list(:+, 1, 2)
# for_each(Cons::list(:+, 1, 2)){|e| p e}
# p map(Cons::list(:+, 1, 2)){|e| e}
p e.myeval(Cons::list(:+, 1, 2))
end
default:
echo "(+ 1 2) (+ 10 3)" | ruby tlisp.rb
class Cons
def car; @e[0]; end
def cdr; @e[1]; end
def initialize(car,cdr)
@e = [car,cdr]
end
def inspect(firstp=true)
if cdr.class == Cons
if firstp
"(#{car.inspect} #{cdr.inspect(false)})"
else
"#{car.inspect} #{cdr.inspect(false)}"
end
elsif cdr.nil?
if firstp
"(#{car.inspect})"
else
"#{car.inspect}"
end
elsif firstp
"(#{car.inspect} . #{cdr.inspect})"
else
"#{car.inspect} . #{cdr.inspect}"
end
end
def self.list(*args)
args.reverse.inject(nil){|acc,e| Cons.new(e, acc)}
end
end
if __FILE__ == $0
p Cons.new(1,nil)
p Cons.new(1,2)
p Cons.new(1, Cons.new(2,3))
p Cons::list()
p Cons::list(1,2,3)
p Cons::list(1,2,3,4,5)
p Cons::list(1,Cons::list(2,3),4)
end
require 'object'
class Lexer
def initialize
end
def lex(s)
s.reverse! ## おかしい。
[].tap do |r|
until s == ""
case s
when /\A\(/ then r << :rp; s = $'
when /\A\d+/ then r << $&.to_i; s = $'
when /\A(\+|\-|\*|\/)/ then r << $1.to_sym; s = $'
when /\A\)/ then r << :lp; s = $'
end
s = $' if s =~ /\A\s+/ #skip
end
end
end
end
class Parser
def initialize
end
def parse(tokens)
r = nil
until tokens.empty?
case e = tokens.shift
when :lp then r = Cons.new(parse(tokens),r)
when :rp then return r
else r = Cons.new(e,r)
end
end
return r
end
end
if __FILE__ == $0
p Lexer.new.lex("1")
p Lexer.new.lex("(2)")
p Lexer.new.lex("((2))")
p Lexer.new.lex("(2 3 4)")
p Lexer.new.lex("(2 (3) 4)")
p "=="
p Parser.new.parse Lexer.new.lex("1")
p Parser.new.parse Lexer.new.lex("(2)")
p Parser.new.parse Lexer.new.lex("((2))")
p Parser.new.parse Lexer.new.lex("(2 3 4)")
p Parser.new.parse Lexer.new.lex("(2 (3) 4)")
p Parser.new.parse Lexer.new.lex("(+ 2 (- 3) 4)")
end
require 'evalator'
require 'parser'
exprs = Parser.new.parse(Lexer.new.lex(STDIN.read))
e = Evalator.new({:+ => lambda{|*args| args.inject(0){|s,n| s + n}}})
for_each(exprs){|expr| p e.myeval(expr)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment