february.lua
· 5.2 KiB · Lua
Brut
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 | })) |