benthos.lua
· 5.5 KiB · Lua
Ham
Playground
local LEFT, RIGHT, LABEL, SYMBOL = 1, 2, 1, 2
local pprint = require "pprint"
local function read_symbol(stream)
local char, symbol = stream(), {}
if not char then return nil end
while char:match("%s") do char = stream() end
while char:match("%S") do table.insert(symbol, char) char = stream() end
return table.concat(symbol)
end
local function print_stacks(stacks)
for key, stack in pairs(stacks) do
io.write(key) io.write(":")
for i = #stack, 1, -1 do
local symbol = stack[i]
io.write(" ") io.write(symbol)
end
io.write("\n")
end
end
local function parse_program(program)
local side, rules, stream = LEFT, {{{}, {}}}, program:gmatch(".")
local label, rule_delimiter
local function push_pair(label, symbol)
table.insert(rules[#rules][side], {label, symbol})
end
while true do
local symbol = read_symbol(stream)
if not symbol then
if label then push_pair(label, "") end
break
elseif not rule_delimiter then
rule_delimiter = symbol
elseif rule_delimiter == symbol then
if label then push_pair(label, "") end
if side == RIGHT then table.insert(rules, {{}, {}}) end
label, side = nil, side == LEFT and RIGHT or LEFT
elseif not label and symbol:sub(1,1) == "/" then
push_pair(symbol:sub(2), "")
elseif not label then
label = symbol
else
push_pair(label, symbol)
label = nil
end
end
if label then push_pair(label, "") end
return rules
end
local function run(rules)
local stacks = {}
for i = #rules, 1, -1 do
local rule = rules[i]
if #rule[LEFT] == 0 then
for _, pair in ipairs(rule[RIGHT]) do
if not stacks[pair[LABEL]] then stacks[pair[LABEL]] = {} end
table.insert(stacks[pair[LABEL]], 1, pair[SYMBOL])
end
table.remove(rules, i)
end
end
local rewrite_happened repeat
rewrite_happened = false
for _, rule in ipairs(rules) do
local retain, bindings, success = {}, {}, true
for _, pattern in ipairs(rule[LEFT]) do
local label, pat = pattern[LABEL], pattern[SYMBOL]
if not stacks[label] then success = false break end
if #stacks[label] == 0 then success = false break end
local symbol = stacks[label][#stacks[label]]
table.remove(stacks[label])
table.insert(retain, {label, symbol})
if pat:sub(1, 1) == "$" then
if not bindings[pat] then
bindings[pat] = symbol
elseif bindings[pat] ~= symbol then
success = false break
end
elseif pat ~= symbol then
success = false break
end
end
rewrite_happened = success
while #retain ~= 0 do
if not success then
local pair = retain[#retain]
table.remove(retain)
table.insert(stacks[pair[LABEL]], pair[SYMBOL])
else
retain = {}
end
end
if success then
for i = #rule[RIGHT], 1, -1 do
local pair = rule[RIGHT][i]
local r_label, r_symbol, binding = pair[LABEL], pair[SYMBOL], bindings[pair[SYMBOL]]
if not stacks[r_label] then stacks[r_label] = {} end
table.insert(stacks[r_label], binding and binding or r_symbol)
end
break
end
end
until not rewrite_happened
print_stacks(stacks)
end
local program = [[
=== === # bubble # sort /#
#list 2
#list 3
#list 1
#list 4
#list 0
=== # bubble # sort /# #list $x #list $y ===
# ord # $x # $y /#
# sort # $x # $y /#
# bubble # sort /#
=== # bubble # sort /# /request.sort ===
# move # ~list # to # list /#
# bubble # sort /#
=== # bubble # sort /# ===
# move # ~list # to # list /#
=== # move # ~list # to # list /# ~list $x ===
# move # ~list # to # list /# #list $x
=== # move # ~list # to # list /# ===
=== # sort # $x # $y /# #ord gt ===
~list $y #list $x
# request # another # sort /#
=== # sort # $x # $y /# #ord eq ===
~list $y ~list $x
=== # sort # $x # $y /# #ord lt ===
~list $x #list $y
=== # request # another # sort /# /request.sort ===
/request.sort
=== # request # another # sort /# ===
/request.sort
=== # ord # 0 # 0 /# === #ord eq
=== # ord # 0 # 1 /# === #ord lt
=== # ord # 0 # 2 /# === #ord lt
=== # ord # 0 # 3 /# === #ord lt
=== # ord # 0 # 4 /# === #ord lt
=== # ord # 1 # 1 /# === #ord eq
=== # ord # 1 # 2 /# === #ord lt
=== # ord # 1 # 3 /# === #ord lt
=== # ord # 1 # 4 /# === #ord lt
=== # ord # 2 # 2 /# === #ord eq
=== # ord # 2 # 3 /# === #ord lt
=== # ord # 2 # 4 /# === #ord lt
=== # ord # 3 # 3 /# === #ord eq
=== # ord # 3 # 4 /# === #ord lt
=== # ord # 4 # 4 /# === #ord eq
=== # ord # $x # $y /# ===
# ord # $y # $x /#
# is # gt /#
=== # is # gt /# #ord lt ===
#ord gt
]]
run(parse_program(program))
1 | local LEFT, RIGHT, LABEL, SYMBOL = 1, 2, 1, 2 |
2 | local pprint = require "pprint" |
3 | local function read_symbol(stream) |
4 | local char, symbol = stream(), {} |
5 | if not char then return nil end |
6 | while char:match("%s") do char = stream() end |
7 | while char:match("%S") do table.insert(symbol, char) char = stream() end |
8 | return table.concat(symbol) |
9 | end |
10 | |
11 | local function print_stacks(stacks) |
12 | for key, stack in pairs(stacks) do |
13 | io.write(key) io.write(":") |
14 | for i = #stack, 1, -1 do |
15 | local symbol = stack[i] |
16 | io.write(" ") io.write(symbol) |
17 | end |
18 | io.write("\n") |
19 | end |
20 | end |
21 | |
22 | local function parse_program(program) |
23 | local side, rules, stream = LEFT, {{{}, {}}}, program:gmatch(".") |
24 | local label, rule_delimiter |
25 | |
26 | local function push_pair(label, symbol) |
27 | table.insert(rules[#rules][side], {label, symbol}) |
28 | end |
29 | |
30 | while true do |
31 | local symbol = read_symbol(stream) |
32 | if not symbol then |
33 | if label then push_pair(label, "") end |
34 | break |
35 | elseif not rule_delimiter then |
36 | rule_delimiter = symbol |
37 | elseif rule_delimiter == symbol then |
38 | if label then push_pair(label, "") end |
39 | if side == RIGHT then table.insert(rules, {{}, {}}) end |
40 | label, side = nil, side == LEFT and RIGHT or LEFT |
41 | elseif not label and symbol:sub(1,1) == "/" then |
42 | push_pair(symbol:sub(2), "") |
43 | elseif not label then |
44 | label = symbol |
45 | else |
46 | push_pair(label, symbol) |
47 | label = nil |
48 | end |
49 | end |
50 | |
51 | if label then push_pair(label, "") end |
52 | |
53 | return rules |
54 | end |
55 | |
56 | local function run(rules) |
57 | local stacks = {} |
58 | for i = #rules, 1, -1 do |
59 | local rule = rules[i] |
60 | if #rule[LEFT] == 0 then |
61 | for _, pair in ipairs(rule[RIGHT]) do |
62 | if not stacks[pair[LABEL]] then stacks[pair[LABEL]] = {} end |
63 | table.insert(stacks[pair[LABEL]], 1, pair[SYMBOL]) |
64 | end |
65 | table.remove(rules, i) |
66 | end |
67 | end |
68 | local rewrite_happened repeat |
69 | rewrite_happened = false |
70 | for _, rule in ipairs(rules) do |
71 | local retain, bindings, success = {}, {}, true |
72 | for _, pattern in ipairs(rule[LEFT]) do |
73 | local label, pat = pattern[LABEL], pattern[SYMBOL] |
74 | if not stacks[label] then success = false break end |
75 | if #stacks[label] == 0 then success = false break end |
76 | |
77 | local symbol = stacks[label][#stacks[label]] |
78 | table.remove(stacks[label]) |
79 | table.insert(retain, {label, symbol}) |
80 | if pat:sub(1, 1) == "$" then |
81 | if not bindings[pat] then |
82 | bindings[pat] = symbol |
83 | elseif bindings[pat] ~= symbol then |
84 | success = false break |
85 | end |
86 | elseif pat ~= symbol then |
87 | success = false break |
88 | end |
89 | end |
90 | rewrite_happened = success |
91 | while #retain ~= 0 do |
92 | if not success then |
93 | local pair = retain[#retain] |
94 | table.remove(retain) |
95 | table.insert(stacks[pair[LABEL]], pair[SYMBOL]) |
96 | else |
97 | retain = {} |
98 | end |
99 | end |
100 | if success then |
101 | for i = #rule[RIGHT], 1, -1 do |
102 | local pair = rule[RIGHT][i] |
103 | local r_label, r_symbol, binding = pair[LABEL], pair[SYMBOL], bindings[pair[SYMBOL]] |
104 | if not stacks[r_label] then stacks[r_label] = {} end |
105 | table.insert(stacks[r_label], binding and binding or r_symbol) |
106 | end |
107 | break |
108 | end |
109 | end |
110 | until not rewrite_happened |
111 | print_stacks(stacks) |
112 | end |
113 | |
114 | local program = [[ |
115 | === === # bubble # sort /# |
116 | #list 2 |
117 | #list 3 |
118 | #list 1 |
119 | #list 4 |
120 | #list 0 |
121 | |
122 | === # bubble # sort /# #list $x #list $y === |
123 | # ord # $x # $y /# |
124 | # sort # $x # $y /# |
125 | # bubble # sort /# |
126 | |
127 | === # bubble # sort /# /request.sort === |
128 | # move # ~list # to # list /# |
129 | # bubble # sort /# |
130 | |
131 | === # bubble # sort /# === |
132 | # move # ~list # to # list /# |
133 | |
134 | === # move # ~list # to # list /# ~list $x === |
135 | # move # ~list # to # list /# #list $x |
136 | |
137 | === # move # ~list # to # list /# === |
138 | |
139 | === # sort # $x # $y /# #ord gt === |
140 | ~list $y #list $x |
141 | # request # another # sort /# |
142 | |
143 | === # sort # $x # $y /# #ord eq === |
144 | ~list $y ~list $x |
145 | |
146 | === # sort # $x # $y /# #ord lt === |
147 | ~list $x #list $y |
148 | |
149 | === # request # another # sort /# /request.sort === |
150 | /request.sort |
151 | |
152 | === # request # another # sort /# === |
153 | /request.sort |
154 | |
155 | === # ord # 0 # 0 /# === #ord eq |
156 | === # ord # 0 # 1 /# === #ord lt |
157 | === # ord # 0 # 2 /# === #ord lt |
158 | === # ord # 0 # 3 /# === #ord lt |
159 | === # ord # 0 # 4 /# === #ord lt |
160 | |
161 | === # ord # 1 # 1 /# === #ord eq |
162 | === # ord # 1 # 2 /# === #ord lt |
163 | === # ord # 1 # 3 /# === #ord lt |
164 | === # ord # 1 # 4 /# === #ord lt |
165 | |
166 | === # ord # 2 # 2 /# === #ord eq |
167 | === # ord # 2 # 3 /# === #ord lt |
168 | === # ord # 2 # 4 /# === #ord lt |
169 | |
170 | === # ord # 3 # 3 /# === #ord eq |
171 | === # ord # 3 # 4 /# === #ord lt |
172 | |
173 | === # ord # 4 # 4 /# === #ord eq |
174 | |
175 | === # ord # $x # $y /# === |
176 | # ord # $y # $x /# |
177 | # is # gt /# |
178 | |
179 | === # is # gt /# #ord lt === |
180 | #ord gt |
181 | ]] |
182 | |
183 | run(parse_program(program)) |