february.lua
· 5.2 KiB · Lua
Raw
Playground
local pprint = require "pprint"
local program = [[
= = @rpn \\ [3] [4] dup * swap dup * swap + sqrt print
= @rpn dup . @rpn.data $ =
@rpn.data \\ $ $
= @rpn swap . @rpn.data \\ $x $y =
@rpn.data \\ $y $x
= @rpn * . @rpn.data \\ $y $x =
@rpn.data $z . @code [$z = $x * $y]
= @rpn + . @rpn.data \\ $y $x =
@rpn.data $z . @code [$z = $x + $y]
= @rpn sqrt . @rpn.data $x =
@rpn.data $y . @code [$y = math.sqrt(tonumber($x))]
= @rpn print . @rpn.data $x =
@code [print($x)]
= @rpn $x =
@rpn.data $x
]]
-- [TODO] make parser module
-- - add symbol parsing hooks (for `[` and `"`)
-- - add symbol stream hooks (for things like `( a b c )`)
-- - add rule steam hooks (for things like `?`)
-- - add post-parsing hooks (for full rule set transformation)
local stream = program:gmatch(".")
local char, rule, rule_symbol, label_symbol, depth, symbol, side, striding
local tuple, rules, LEFT, RIGHT = {}, {}, 1, 2
repeat
rule_symbol, char = "", stream()
side, rule = LEFT, {{}, {}}
while char and char:match("[%s%.,]") do
-- skip all characters that can't be bound
char = stream()
end
if char == nil then
break
elseif char == "[" then
-- rule delimiter is multibyte
depth, char = 1, stream()
while char do
if char == "[" then depth = depth + 1 end
if char == "]" then depth = depth - 1 end
if depth == 0 then break end
rule_symbol, char = rule_symbol .. char, stream()
end
else
-- rule delimiter is a single character
rule_symbol = "" while char and not char:match("%s") do
rule_symbol, char = rule_symbol .. char, stream() if char == "[" then
io.stderr:write "Warning: symbol contains `[`. A space may be missing?"
end
end
end
repeat -- consume rules from this set
char = stream()
while char and (char:match("[%s]") or not label_symbol and char:match("[%.,]")) do
-- skip whitespace or [.,] if a label hasn't been selected
char = stream()
end
if not char then
if label_symbol and not striding then
table.insert(rule[side], {label_symbol, tuple})
end
break
end
-- read a symbol from the stream
if char:match("[%.,]") then
-- we've hit a tuple related delimiter
symbol = char
elseif char == "[" then
-- parse a boxed symbol
symbol, depth, char = "", 1, stream() while char do
if char == "[" then depth = depth + 1 end
if char == "]" then depth = depth - 1 end
if depth == 0 then break end
symbol, char = symbol .. char, stream()
end
else
-- parse a symbol seperated by spaces
-- this segment warns if a symbol contains `[`
symbol = "" while char and not char:match("%s") do
symbol, char = symbol .. char, stream() if char == "[" then
io.stderr:write "Warning: symbol contains `[`. A space may be missing?"
end
end
end
-- process that symbol
if symbol == "," then
-- push a tuple
table.insert(rule[side], {label_symbol, tuple})
striding, tuple = false, {}
elseif symbol == "." then
-- push a tuple, clear label symbol
if not (striding and #tuple == 0) then
table.insert(rule[side], {label_symbol, tuple})
end
striding, tuple, label_symbol = false, {}, nil
elseif symbol == [[\\]] then
if #tuple ~= 0 then
table.insert(rule[side], {label_symbol, tuple})
tuple = {}
end
striding = true
elseif symbol == rule_symbol and side == RIGHT then
if label_symbol and not (striding and #tuple == 0) then
table.insert(rule[side], {label_symbol, tuple})
tuple = {}
end
if #rule[LEFT] == 0 and #rule[RIGHT] == 0 then
break
else
table.insert(rules, rule)
striding, side, rule, label_symbol = false, LEFT, {{}, {}}, nil
end
elseif symbol == rule_symbol and side == LEFT then
-- a rule dilimiter
if label_symbol and not (striding and #tuple == 0) then
table.insert(rule[side], {label_symbol, tuple})
end
striding, tuple, side, label_symbol = false, {}, RIGHT, nil
elseif not label_symbol then
-- a label s symbol
label_symbol = symbol
elseif striding then
table.insert(rule[side], {label_symbol, {symbol}})
else
-- a symbol in a tuple
table.insert(tuple, symbol)
end
until not char
if #rule[LEFT] ~= 0 or #rule[RIGHT] ~= 0 then
table.insert(rules, rule)
end
until not char
local compile = require "compiler"
print(compile(rules, {
mode = "main",
state_every_rewrite = false,
state_at_start = true,
state_at_end = true,
}))
1 | local pprint = require "pprint" |
2 | local program = [[ |
3 | = = @rpn \\ [3] [4] dup * swap dup * swap + sqrt print |
4 | |
5 | = @rpn dup . @rpn.data $ = |
6 | @rpn.data \\ $ $ |
7 | |
8 | = @rpn swap . @rpn.data \\ $x $y = |
9 | @rpn.data \\ $y $x |
10 | |
11 | = @rpn * . @rpn.data \\ $y $x = |
12 | @rpn.data $z . @code [$z = $x * $y] |
13 | |
14 | = @rpn + . @rpn.data \\ $y $x = |
15 | @rpn.data $z . @code [$z = $x + $y] |
16 | |
17 | = @rpn sqrt . @rpn.data $x = |
18 | @rpn.data $y . @code [$y = math.sqrt(tonumber($x))] |
19 | |
20 | = @rpn print . @rpn.data $x = |
21 | @code [print($x)] |
22 | |
23 | = @rpn $x = |
24 | @rpn.data $x |
25 | ]] |
26 | -- [TODO] make parser module |
27 | -- - add symbol parsing hooks (for `[` and `"`) |
28 | -- - add symbol stream hooks (for things like `( a b c )`) |
29 | -- - add rule steam hooks (for things like `?`) |
30 | -- - add post-parsing hooks (for full rule set transformation) |
31 | local stream = program:gmatch(".") |
32 | local char, rule, rule_symbol, label_symbol, depth, symbol, side, striding |
33 | local tuple, rules, LEFT, RIGHT = {}, {}, 1, 2 |
34 | repeat |
35 | rule_symbol, char = "", stream() |
36 | side, rule = LEFT, {{}, {}} |
37 | while char and char:match("[%s%.,]") do |
38 | -- skip all characters that can't be bound |
39 | char = stream() |
40 | end |
41 | if char == nil then |
42 | break |
43 | elseif char == "[" then |
44 | -- rule delimiter is multibyte |
45 | depth, char = 1, stream() |
46 | while char do |
47 | if char == "[" then depth = depth + 1 end |
48 | if char == "]" then depth = depth - 1 end |
49 | if depth == 0 then break end |
50 | rule_symbol, char = rule_symbol .. char, stream() |
51 | end |
52 | else |
53 | -- rule delimiter is a single character |
54 | rule_symbol = "" while char and not char:match("%s") do |
55 | rule_symbol, char = rule_symbol .. char, stream() if char == "[" then |
56 | io.stderr:write "Warning: symbol contains `[`. A space may be missing?" |
57 | end |
58 | end |
59 | end |
60 | repeat -- consume rules from this set |
61 | char = stream() |
62 | while char and (char:match("[%s]") or not label_symbol and char:match("[%.,]")) do |
63 | -- skip whitespace or [.,] if a label hasn't been selected |
64 | char = stream() |
65 | end |
66 | if not char then |
67 | if label_symbol and not striding then |
68 | table.insert(rule[side], {label_symbol, tuple}) |
69 | end |
70 | break |
71 | end |
72 | -- read a symbol from the stream |
73 | if char:match("[%.,]") then |
74 | -- we've hit a tuple related delimiter |
75 | symbol = char |
76 | elseif char == "[" then |
77 | -- parse a boxed symbol |
78 | symbol, depth, char = "", 1, stream() while char do |
79 | if char == "[" then depth = depth + 1 end |
80 | if char == "]" then depth = depth - 1 end |
81 | if depth == 0 then break end |
82 | symbol, char = symbol .. char, stream() |
83 | end |
84 | else |
85 | -- parse a symbol seperated by spaces |
86 | -- this segment warns if a symbol contains `[` |
87 | symbol = "" while char and not char:match("%s") do |
88 | symbol, char = symbol .. char, stream() if char == "[" then |
89 | io.stderr:write "Warning: symbol contains `[`. A space may be missing?" |
90 | end |
91 | end |
92 | end |
93 | -- process that symbol |
94 | if symbol == "," then |
95 | -- push a tuple |
96 | table.insert(rule[side], {label_symbol, tuple}) |
97 | striding, tuple = false, {} |
98 | elseif symbol == "." then |
99 | -- push a tuple, clear label symbol |
100 | if not (striding and #tuple == 0) then |
101 | table.insert(rule[side], {label_symbol, tuple}) |
102 | end |
103 | striding, tuple, label_symbol = false, {}, nil |
104 | elseif symbol == [[\\]] then |
105 | if #tuple ~= 0 then |
106 | table.insert(rule[side], {label_symbol, tuple}) |
107 | tuple = {} |
108 | end |
109 | striding = true |
110 | elseif symbol == rule_symbol and side == RIGHT then |
111 | if label_symbol and not (striding and #tuple == 0) then |
112 | table.insert(rule[side], {label_symbol, tuple}) |
113 | tuple = {} |
114 | end |
115 | if #rule[LEFT] == 0 and #rule[RIGHT] == 0 then |
116 | break |
117 | else |
118 | table.insert(rules, rule) |
119 | striding, side, rule, label_symbol = false, LEFT, {{}, {}}, nil |
120 | end |
121 | elseif symbol == rule_symbol and side == LEFT then |
122 | -- a rule dilimiter |
123 | if label_symbol and not (striding and #tuple == 0) then |
124 | table.insert(rule[side], {label_symbol, tuple}) |
125 | end |
126 | striding, tuple, side, label_symbol = false, {}, RIGHT, nil |
127 | elseif not label_symbol then |
128 | -- a label s symbol |
129 | label_symbol = symbol |
130 | elseif striding then |
131 | table.insert(rule[side], {label_symbol, {symbol}}) |
132 | else |
133 | -- a symbol in a tuple |
134 | table.insert(tuple, symbol) |
135 | end |
136 | until not char |
137 | if #rule[LEFT] ~= 0 or #rule[RIGHT] ~= 0 then |
138 | table.insert(rules, rule) |
139 | end |
140 | until not char |
141 | |
142 | local compile = require "compiler" |
143 | |
144 | print(compile(rules, { |
145 | mode = "main", |
146 | state_every_rewrite = false, |
147 | state_at_start = true, |
148 | state_at_end = true, |
149 | })) |