The goal of stage 06 is to try parse zig synax in lua. I pulled in lpeglable 1.2.0 and parser-gen off github to get started. All of this needs to be cleaned up rather soon. Lua boostraps using tcc and musl from the previous stage. Since musl 0.6.0 doesn't support dynamic linking this build of lua doesn't support shared libraries. I couldn't easily patch musl with dlopen and friends so instead I link statically and call deps with c api.
122 lines
2.6 KiB
Lua
122 lines
2.6 KiB
Lua
local m = require"lpeglabel"
|
|
local re = require"relabel"
|
|
|
|
local num = m.R("09")^1 / tonumber
|
|
local op = m.S("+-")
|
|
|
|
local labels = {}
|
|
local nlabels = 0
|
|
|
|
local function newError(lab, msg, psync, pcap)
|
|
nlabels = nlabels + 1
|
|
psync = psync or m.P(-1)
|
|
pcap = pcap or m.P""
|
|
labels[lab] = { id = nlabels, msg = msg, psync = psync, pcap = pcap }
|
|
end
|
|
|
|
newError("ExpTermFirst", "expected an expression", op + ")", m.Cc(1000))
|
|
newError("ExpTermOp", "expected a term after the operator", op + ")", m.Cc(1000))
|
|
newError("MisClose", "missing a closing ')' after the expression", m.P")")
|
|
newError("Extra", "extra characters found after the expression")
|
|
|
|
local errors, subject
|
|
|
|
local function expect(patt, labname)
|
|
local i = labels[labname].id
|
|
return patt + m.T(i)
|
|
end
|
|
|
|
local function compute(tokens)
|
|
local result = tokens[1]
|
|
for i = 2, #tokens, 2 do
|
|
if tokens[i] == '+' then
|
|
result = result + tokens[i+1]
|
|
elseif tokens[i] == '-' then
|
|
result = result - tokens[i+1]
|
|
else
|
|
error('unknown operation: ' .. tokens[i])
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
local g = m.P {
|
|
"Exp",
|
|
Exp = m.Ct(m.V"OperandFirst" * (m.C(op) * m.V"Operand")^0) / compute,
|
|
OperandFirst = expect(m.V"Term", "ExpTermFirst"),
|
|
Operand = expect(m.V"Term", "ExpTermOp"),
|
|
Term = num + m.V"Group",
|
|
Group = "(" * m.V"Exp" * expect(")", "MisClose"),
|
|
}
|
|
|
|
function recorderror(pos, lab)
|
|
local line, col = re.calcline(subject, pos)
|
|
table.insert(errors, { line = line, col = col, msg = labels[lab].msg })
|
|
end
|
|
|
|
function record (labname)
|
|
return (m.Cp() * m.Cc(labname)) / recorderror
|
|
end
|
|
|
|
function sync (p)
|
|
return (-p * m.P(1))^0
|
|
end
|
|
|
|
function defaultValue (p)
|
|
return p or m.Cc(1000)
|
|
end
|
|
|
|
local grec = g * expect(m.P(-1), "Extra")
|
|
for k, v in pairs(labels) do
|
|
grec = m.Rec(grec, record(k) * sync(v.psync) * v.pcap, v.id)
|
|
end
|
|
|
|
local function eval(input)
|
|
errors = {}
|
|
io.write("Input: ", input, "\n")
|
|
subject = input
|
|
local result, label, suffix = grec:match(input)
|
|
io.write("Syntactic errors found: " .. #errors, "\n")
|
|
if #errors > 0 then
|
|
local out = {}
|
|
for i, err in ipairs(errors) do
|
|
local pos = err.col
|
|
local msg = err.msg
|
|
table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
|
|
end
|
|
print(table.concat(out, "\n"))
|
|
end
|
|
io.write("Result = ")
|
|
return result
|
|
end
|
|
|
|
print(eval "90-70-(5)+3")
|
|
--> 18
|
|
|
|
print(eval "15+")
|
|
--> 2 + 0
|
|
|
|
print(eval "-2")
|
|
--> 0 - 2
|
|
|
|
print(eval "1+3+-9")
|
|
--> 1 + 3 + [0] - 9
|
|
|
|
print(eval "1+()3+")
|
|
--> 1 + ([0]) [+] 3 + [0]
|
|
|
|
print(eval "8-(2+)-5")
|
|
--> 8 - (2 + [0]) - 5
|
|
|
|
print(eval "()")
|
|
|
|
print(eval "")
|
|
|
|
print(eval "1+()+")
|
|
|
|
print(eval "1+(")
|
|
|
|
print(eval "3)")
|
|
|
|
print(eval "11+()3")
|
|
--> 1 + ([0]) [+] 3 + [0]
|