-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompiler.rb
72 lines (68 loc) · 1.99 KB
/
compiler.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
def tokenize input
unless input[0] == '(' and input[-1] == ')'
raise SyntaxError, "Lisp command should start with '(' and end with ')'"
end
tokens = input.gsub!('(', '( ').gsub!(')', ' )').split
(0...tokens.length).each do |indx|
case tokens[indx]
when '('
tokens[indx] = {type: 'paren', value: '('}
when ')'
tokens[indx] = {type: 'paren', value: ')'}
when /^([0-9])/
tokens[indx] = {type: 'number', value: tokens[indx]}
when /[a-z]/i
tokens[indx] = {type: 'name', value: tokens[indx]}
end
end
return tokens
end
def make_tree
token = @tokens[@current]
if token[:type] == 'number'
@current += 1
return {type: 'NumberLiteral', value: token[:value]}
end
if token[:value] == '('
token = @tokens[@current += 1]
node = {type: 'CallExpression', callee: {type: 'Identifier', name: token[:value]}, arguments: []}
token = @tokens[@current += 1]
while token[:value] != ')'
node[:arguments] << make_tree
token = @tokens[@current]
end
@current += 1
return node
end
end
def parser
@current = 0
ast = {type: 'Program', body: []}
while (@current < @tokens.length)
ast[:body] << make_tree
end
return ast
end
def code_generate node
case node[:type]
when 'Program'
return node[:body].map{|node| code_generate node}.join("\n")
when 'CallExpression'
return (code_generate(node[:callee]) + '(' +
node[:arguments].map{|node| code_generate node}.join(', ') + ')')
when 'Identifier'
return node[:name]
when 'NumberLiteral'
return node[:value]
end
end
def run_compiler
while true
print "Lisp--> C >> "
input = gets.chomp
break if input.downcase == 'break'
@tokens = tokenize input
puts "#{code_generate parser};\n\n"
end
end
run_compiler