mirror of
https://github.com/vonhyou/lisp-interpreter.git
synced 2025-06-08 02:02:01 +00:00
finish calucator
This commit is contained in:
parent
4f7bbe8129
commit
478e6e4e5d
1 changed files with 84 additions and 13 deletions
97
minlisp.rb
97
minlisp.rb
|
@ -2,6 +2,17 @@
|
|||
# Author: @vonhyou
|
||||
# Start at: Apr. 10, 2021
|
||||
|
||||
##### Parser
|
||||
# :parse
|
||||
# :tokenize
|
||||
# :read_tokens
|
||||
# :atom
|
||||
#####
|
||||
|
||||
def parse(program)
|
||||
read_tokens(tokenize(program))
|
||||
end
|
||||
|
||||
def tokenize(program)
|
||||
# Convert scripts to token lists
|
||||
replacements = { '(' => ' ( ', ')' => ' ) ' }
|
||||
|
@ -9,30 +20,90 @@ def tokenize(program)
|
|||
.split(' ')
|
||||
end
|
||||
|
||||
def make_list(tokens)
|
||||
lst = []
|
||||
lst << read_tokens(tokens) while tokens[0] != ')'
|
||||
tokens.shift
|
||||
lst
|
||||
end
|
||||
|
||||
def read_tokens(tokens)
|
||||
# read expressions from token
|
||||
raise SyntaxError, 'Unexpected EOF' if tokens.empty?
|
||||
|
||||
token = tokens.shift
|
||||
if token == '('
|
||||
lst = []
|
||||
lst << read_tokens(tokens) while tokens[0] != ')'
|
||||
tokens.shift
|
||||
return lst
|
||||
elsif token == ')'
|
||||
case token
|
||||
when '('
|
||||
make_list tokens
|
||||
when ')'
|
||||
raise SyntaxError, "Unexpected ')'"
|
||||
else
|
||||
return atom token
|
||||
atom token
|
||||
end
|
||||
end
|
||||
|
||||
def isInteger?(atom) = atom.match?(/^-?\d+$/)
|
||||
def isFloat?(atom) = atom.match?(/^(-?\d+)(\.\d+)?$/)
|
||||
|
||||
def atom(token)
|
||||
# Analyse numbers and symbols
|
||||
return Integer token if isInteger? token
|
||||
return Float token if isFloat? token
|
||||
token
|
||||
isInteger = ->(atom) { atom.match?(/^-?\d+$/) }
|
||||
isFloat = ->(atom) { atom.match?(/^(-?\d+)(\.\d+)?$/) }
|
||||
return Integer token if isInteger.call token
|
||||
return Float token if isFloat.call token
|
||||
|
||||
token.to_sym
|
||||
end
|
||||
|
||||
# p parse '(def 1 2 (c 3.3 (r f r) e))'
|
||||
|
||||
|
||||
##### Environments
|
||||
|
||||
def generate_env
|
||||
lisp_env = {
|
||||
'+': ->(arr) { arr.sum }, # args.inject(0, :+)
|
||||
'-': ->(*args) { eval args.join('-') },
|
||||
'*': ->(*args) { eval args.join('*') },
|
||||
'/': ->(*args) { eval args.join('/') },
|
||||
'>': ->(x, y) { x > y },
|
||||
'<': ->(x, y) { x < y },
|
||||
'=': ->(x, y) { x == y },
|
||||
'>=': ->(x, y) { x >= y },
|
||||
'<=': ->(x, y) { x <= y },
|
||||
'min': ->(*args) { args.min },
|
||||
'max': ->(*args) { args.max },
|
||||
'car': ->(arr) { arr[0] },
|
||||
'cdr': ->(arr) { arr[1..-1] }
|
||||
}
|
||||
end
|
||||
|
||||
# puts lisp_env[:+].call 1, 2, 3
|
||||
# puts lisp_env[:-].call 1, 2, 3
|
||||
# puts lisp_env[:*].call 2, 3, 4
|
||||
# puts lisp_env[:/].call 9, 5, 1
|
||||
# puts lisp_env[:>].call 1, 2
|
||||
|
||||
# p lisp_env[:car].call [1, 2, 3]
|
||||
# p lisp_env[:cdr].call [1, 2, 3]
|
||||
|
||||
def do_sth ; end
|
||||
|
||||
##### Lisp Eval
|
||||
|
||||
def lisp_eval(elem, env = generate_env)
|
||||
if elem.instance_of?(Symbol)
|
||||
env[elem]
|
||||
elsif elem.instance_of?(Integer) || elem.instance_of?(Float)
|
||||
elem
|
||||
elsif elem[0] == :def
|
||||
do_sth
|
||||
elsif elem[0] == :if
|
||||
do_sth
|
||||
else
|
||||
args = []
|
||||
elem[1..-1].each { |arg| args << lisp_eval(arg, env) }
|
||||
p lisp_eval(elem[0], env)
|
||||
lisp_eval(elem[0], env).call args
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
p lisp_eval(parse '(/ (+ 1 (* 2 3) 1 1 (+ 1 (- 7 2) 1)) 4)')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue