Last active
January 3, 2016 22:29
-
-
Save threedaymonk/8528281 to your computer and use it in GitHub Desktop.
Little Schemer group, chapter 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.dot |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(car (cons 1 (list 2 3))) | |
(list 4 5) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.PHONY: clean all | |
all: diag.pdf | |
diag.dot: example.scm | |
ruby ./vis.rb < example.scm > diag.dot | |
diag.pdf: diag.dot | |
dot -Tpdf < diag.dot > diag.pdf | |
clean: | |
rm -f diag.dot diag.pdf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "./parser" | |
p Parser.parse_program($stdin.read) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'strscan' | |
module Parser | |
module_function | |
def parse_expression(scanner) | |
if scanner.scan(/\(/) | |
parse_list(scanner) | |
elsif scanner.scan(/\s/) | |
return :space | |
elsif scanner.scan(/\)/) | |
return :rparen | |
elsif str = scanner.scan(/[^\s\(\)]+/) | |
return parse_atom(str) | |
elsif scanner.eos? | |
return :eos | |
else | |
raise "dunno before #{scanner.rest}" | |
end | |
end | |
def parse_atom(str) | |
return str | |
end | |
def parse_list(scanner) | |
list = [] | |
loop do | |
element = parse_expression(scanner) | |
case element | |
when :rparen | |
return list | |
when :space | |
# ignore me | |
when :eos | |
raise "unexpected end of input" | |
else | |
list << element | |
end | |
end | |
raise "unbalanced parentheses before #{scanner.rest}" | |
end | |
def parse_program(string) | |
scanner = StringScanner.new(string) | |
list = [] | |
loop do | |
element = parse_expression(scanner) | |
case element | |
when :eos | |
return list | |
when :space | |
# ignore me | |
else | |
list << element | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "./parser.rb" | |
def label_node(node) | |
if node.respond_to?(:each) | |
%(a#{node.object_id} [label="List" shape="rect"]) | |
else | |
%(a#{node.object_id} [label="#{node.inspect.gsub(/"/, "'")}"];) | |
end | |
end | |
def render_edges(structure, acc = []) | |
structure.each do |e| | |
acc << label_node(structure) | |
acc << label_node(e) | |
acc << "a#{structure.object_id} -> a#{e.object_id};" | |
if e.respond_to?(:each) | |
render_edges(e, acc) | |
end | |
end | |
acc | |
end | |
structure = Parser.parse_program($stdin.read) | |
puts "digraph G {" | |
puts render_edges(structure).join("\n") | |
puts "}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment