commit
378842b52e
5 changed files with 910 additions and 0 deletions
-
168brainfuck_parse.lua
-
172o_brainfuck.lua
-
127o_pbx_brainfuck.lua
-
382parse_manifest.lua
-
61parse_table.lua
@ -0,0 +1,168 @@ |
|||
local node_plus_const = function(tape_offset, amount) |
|||
return |
|||
{ |
|||
nodetype = "plus", |
|||
pure = true, |
|||
left = {valtype = "tape", offset = tape_offset}, |
|||
right = {valtype = "immediate", value = amount}, |
|||
out = {valtype = "tape", offset = tape_offset}, |
|||
temporal_dependencies = {}, |
|||
pure_dependencies = {}, |
|||
} |
|||
end |
|||
|
|||
local node_out = function(tape_offset) |
|||
return |
|||
{ |
|||
nodetype = "out", |
|||
pure = false, |
|||
input = { valtype = "tape", offset = tape_offset }, |
|||
temporal_dependencies = {}, |
|||
pure_dependencies = {}, |
|||
} |
|||
end |
|||
|
|||
local node_in = function(tape_offset) |
|||
return |
|||
{ |
|||
nodetype = "in", |
|||
pure = false, |
|||
output = { valtype = "tape", offset = tape_offset }, |
|||
temporal_dependencies = {}, |
|||
pure_dependencies = {}, |
|||
} |
|||
end |
|||
|
|||
local node_root = function() |
|||
return |
|||
{ |
|||
nodetype = "root", |
|||
pure = true, |
|||
temporal_dependencies = {}, |
|||
pure_dependencies = {} |
|||
} |
|||
end |
|||
|
|||
local func_tab = |
|||
{ |
|||
[1] = function(t) |
|||
t.head_pos = t.head_pos - 1 |
|||
t.idx = t.idx + 1 |
|||
end, |
|||
[2] = function(t) |
|||
t.head_pos = t.head_pos + 1 |
|||
t.idx = t.idx + 1 |
|||
end, |
|||
[3] = function(t) |
|||
local node = node_plus_const(tape_offset, 1) |
|||
node.temporal_dependencies = { t.current_node } |
|||
t.current_node = node |
|||
t.idx = t.idx + 1 |
|||
end, |
|||
[4] = function(t) |
|||
local node = node_plus_const(tape_offset, 1) |
|||
node.temporal_dependencies = { t.current_node } |
|||
t.current_node = node |
|||
t.idx = t.idx + 1 |
|||
end, |
|||
[5] = function(t) |
|||
local node = node_out(tape_offset) |
|||
node.temporal_dependencies = { t.current_node } |
|||
t.current_node = node |
|||
t.idx = t.idx + 1 |
|||
end, |
|||
[6] = function(t) |
|||
local node = node_in(tape_offset) |
|||
node.temporal_dependencies = { t.current_node } |
|||
t.current_node = node |
|||
t.idx = t.idx + 1 |
|||
end, |
|||
[7] = function(t) |
|||
error("unimplemented") |
|||
end, |
|||
[8] = function(t) |
|||
error("unimplemented") |
|||
end, |
|||
-- [nil] = function(t) |
|||
-- t.ret_idx = t.idx |
|||
-- end, |
|||
} |
|||
|
|||
function do_parse_seq(sequence, idx) |
|||
local t = |
|||
{ |
|||
sym = sequence[idx], |
|||
ret_idx = nil, |
|||
idx = idx, |
|||
head_pos = 0, |
|||
current_node = node_root(), |
|||
} |
|||
|
|||
while t.ret_idx == nil do |
|||
func_tab[t.sym](t) |
|||
t.sym = sequence[t.idx] |
|||
if t.sym == nil then |
|||
t.ret_idx = t.idx |
|||
end |
|||
end |
|||
|
|||
return t |
|||
end |
|||
|
|||
function io_to_string(io) |
|||
if io.valtype == "immediate" then |
|||
return tostring(io.value) |
|||
elseif io.valtype == "tape" then |
|||
return "tape[" .. tostring(io.offset) .. "]" |
|||
else |
|||
return "unknown i/o" |
|||
end |
|||
end |
|||
|
|||
function recursive_node_string(node) |
|||
if node.nodetype == "root" then |
|||
return { "root" } |
|||
elseif node.nodetype == "plus" then |
|||
local dep = recursive_node_string(node.temporal_dependencies[1]) |
|||
table.insert(dep, "add " .. io_to_string(node.left) .. " + " .. io_to_string(node.right)) |
|||
return dep |
|||
elseif node.nodetype == "out" then |
|||
local dep = recursive_node_string(node.temporal_dependencies[1]) |
|||
table.insert(dep, "out " .. io_to_string(node.input)) |
|||
return dep |
|||
elseif node.nodetype == "in" then |
|||
local dep = recursive_node_string(node.temporal_dependencies[1]) |
|||
table.insert(dep, "in " .. tostring(node.output)) |
|||
return dep |
|||
else |
|||
return { "unknown node" } |
|||
end |
|||
end |
|||
|
|||
--str = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." |
|||
--str = "+[-]..." |
|||
str = ".+.>.+.<.-.>.-." |
|||
--str = "+[+]" |
|||
|
|||
char_table = |
|||
{ |
|||
[">"] = 1, |
|||
["<"] = 2, |
|||
["+"] = 3, |
|||
["-"] = 4, |
|||
["."] = 5, |
|||
[","] = 6, |
|||
["["] = 7, |
|||
["]"] = 8, |
|||
} |
|||
|
|||
prog = {} |
|||
|
|||
for i = 1,#str do |
|||
prog[#prog + 1] = char_table[string.sub(str, i, i)] |
|||
end |
|||
|
|||
local q = do_parse_seq(prog, 1) |
|||
|
|||
print(table.concat(recursive_node_string(q.current_node), "\n")) |
|||
|
@ -0,0 +1,172 @@ |
|||
local look_for_closing_brace = function(context, idx) |
|||
if context.matching_indices[idx] ~= nil then |
|||
return context.matching_indices[idx] |
|||
end |
|||
local orig_idx = idx |
|||
local layer = 1 |
|||
while layer ~= 0 do |
|||
idx = idx + 1 |
|||
if context.program[idx] == nil then |
|||
return -1 |
|||
end |
|||
if context.program[idx] == 7 then |
|||
layer = layer + 1 |
|||
end |
|||
if context.program[idx] == 8 then |
|||
layer = layer - 1 |
|||
end |
|||
end |
|||
context.matching_indices[orig_idx] = idx |
|||
return idx |
|||
end |
|||
|
|||
local init_tape_at_head = function(context) |
|||
if context.tape[context.head_pos] == nil then |
|||
context.tape[context.head_pos] = context.initial_tape_func(context.head_pos) |
|||
end |
|||
end |
|||
|
|||
local loop_jump = function(context) |
|||
init_tape_at_head(context) |
|||
if context.tape[context.head_pos] ~= 0 then |
|||
context.ip = context.jumpstack_left[#context.jumpstack_left] + 1 |
|||
else |
|||
local idx = #context.jumpstack_left |
|||
context.jumpstack_left[idx] = nil |
|||
context.jumpstack_right[idx] = nil |
|||
context.ip = context.ip + 1 |
|||
end |
|||
end |
|||
|
|||
local do_open_bracket = function(context) |
|||
context.jumpstack_left[#context.jumpstack_left + 1] = context.ip |
|||
context.jumpstack_right[#context.jumpstack_left] = look_for_closing_brace(context, context.ip) |
|||
context.ip = context.jumpstack_right[#context.jumpstack_left] |
|||
loop_jump(context) |
|||
end |
|||
|
|||
local do_close_bracket = function(context) |
|||
if context.jumpstack_right[#context.jumpstack_left] == context.ip then |
|||
loop_jump(context) |
|||
else |
|||
context.retval = {kind = "error", value = "unexpected right bracket"} |
|||
end |
|||
end |
|||
|
|||
local instr_table = |
|||
{ |
|||
[1] = function(context) |
|||
context.head_pos = context.head_pos - 1 |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
[2] = function(context) |
|||
context.head_pos = context.head_pos + 1 |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
[3] = function(context) |
|||
init_tape_at_head(context) |
|||
context.tape[context.head_pos] = context.tape[context.head_pos] + 1 |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
[4] = function(context) |
|||
init_tape_at_head(context) |
|||
context.tape[context.head_pos] = context.tape[context.head_pos] - 1 |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
[5] = function(context) |
|||
init_tape_at_head(context) |
|||
context.write(context.tape[context.head_pos]) |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
[6] = function(context) |
|||
context.tape[context.head_pos] = context.read() |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
[7] = do_open_bracket, |
|||
[8] = do_close_bracket, |
|||
[9] = function(context) |
|||
context.debugfn(context.head_pos, context.ip, context.tape) |
|||
context.ip = context.ip + 1 |
|||
end, |
|||
} |
|||
|
|||
local step = function(context, app) |
|||
local f = instr_table[context.program[context.ip]] |
|||
if f == nil then |
|||
context.retval = {kind = "return", value = "success"} |
|||
else |
|||
f(context) |
|||
end |
|||
end |
|||
|
|||
function new_brainfuck_context(log, program, write, read, debugfn, initial_tape_func) |
|||
local context = |
|||
{ |
|||
program = program, |
|||
write = write, |
|||
read = read, |
|||
debugfn = debugfn, |
|||
log = log, |
|||
initial_tape_func = initial_tape_func, |
|||
|
|||
head_pos = 0, |
|||
tape = {}, |
|||
ip = 1, |
|||
jumpstack_left = {}, |
|||
jumpstack_right = {}, |
|||
|
|||
matching_indices = {}, |
|||
|
|||
retval = nil, |
|||
} |
|||
context.step = step |
|||
return context |
|||
end |
|||
|
|||
return { new_brainfuck_context = new_brainfuck_context } |
|||
|
|||
--[[ |
|||
--str = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." |
|||
--str = "+[-]..." |
|||
--str = ".+.>.+.<.-.>.-." |
|||
str = "+[+]" |
|||
|
|||
char_table = |
|||
{ |
|||
[">"] = 1, |
|||
["<"] = 2, |
|||
["+"] = 3, |
|||
["-"] = 4, |
|||
["."] = 5, |
|||
[","] = 6, |
|||
["["] = 7, |
|||
["]"] = 8, |
|||
} |
|||
|
|||
prog = {} |
|||
|
|||
for i = 1,#str do |
|||
prog[#prog + 1] = char_table[string.sub(str, i, i)] |
|||
end |
|||
out = "" |
|||
unmangled = "" |
|||
|
|||
context = new_brainfuck_context(prog, function(v) |
|||
out = out .. " " .. tostring(v) |
|||
unmangled = unmangled .. string.char(v) |
|||
end, function() return 0 end, function() return 0 end) |
|||
|
|||
count = 0 |
|||
while context.retval == nil and count < 1000000 do |
|||
context:step() |
|||
count = count + 1 |
|||
end |
|||
tab = context.retval |
|||
|
|||
if tab.kind == "return" then |
|||
print(out) |
|||
print(unmangled) |
|||
elseif tab.kind == "error" then |
|||
print("error: " .. tab.value) |
|||
end |
|||
--]] |
@ -0,0 +1,127 @@ |
|||
bf = require("o_brainfuck") |
|||
espeak = require("espeak") |
|||
|
|||
local get_prog = function() |
|||
channel.TIMEOUT("response"):set(60) |
|||
app.read("up_prog", "", 0, "", 1, 1e6) |
|||
local up_prog = channel.up_prog:get() |
|||
|
|||
local program = {} |
|||
local dig_tab = |
|||
{ |
|||
["1"] = 1, |
|||
["2"] = 2, |
|||
["3"] = 3, |
|||
["4"] = 4, |
|||
["5"] = 5, |
|||
["6"] = 6, |
|||
["7"] = 7, |
|||
["8"] = 8, |
|||
["*"] = 9, |
|||
} |
|||
app.verbose(3, "running Brainfuck program: " .. up_prog) |
|||
for i=1,#up_prog do |
|||
local sym = string.sub(up_prog, i, i) |
|||
if sym == "9" and #program > 0 then |
|||
program[#program] = nil |
|||
else |
|||
if dig_tab[sym] ~= nil then |
|||
program[#program + 1] = dig_tab[sym] |
|||
end |
|||
end |
|||
end |
|||
return program |
|||
end |
|||
|
|||
|
|||
|
|||
local read_number_context = function(program, globals) |
|||
local read = function() |
|||
app.read("input_digit", "", 0, "", 1, 1e6) |
|||
local convert_tab = |
|||
{ |
|||
["0"] = 0, |
|||
["1"] = 1, |
|||
["2"] = 2, |
|||
["3"] = 3, |
|||
["4"] = 4, |
|||
["5"] = 5, |
|||
["6"] = 6, |
|||
["7"] = 7, |
|||
["8"] = 8, |
|||
["9"] = 9, |
|||
["*"] = 10, |
|||
["#"] = 11, |
|||
} |
|||
local digit = channel.input_digit:get() |
|||
local num = tonumber(digit) |
|||
if nil == num then |
|||
globals.err = "hung up" |
|||
return nil |
|||
end |
|||
|
|||
return num |
|||
end |
|||
|
|||
local write = function(n) |
|||
app.checkhangup() |
|||
if channel.HUNGUP:get() == "HUNGUP" then |
|||
globals.err = "hung up" |
|||
else |
|||
espeak(tostring(n)) |
|||
end |
|||
end |
|||
|
|||
local debug = function(head_pos, ip, tape) |
|||
app.verbose(3, "brainfuck program invoked debug\n"); |
|||
espeak("DEBUG INFO") |
|||
espeak("head position: " .. tostring(head_pos)) |
|||
espeak("instruction pointer: " .. tostring(ip)) |
|||
espeak("tape:") |
|||
for k, v in pairs(tape) do |
|||
espeak("at " .. tostring(k) .. " is " .. tostring(v)) |
|||
end |
|||
end |
|||
|
|||
return bf.new_brainfuck_context(function(m) app.verbose(3, m) end, program, write, read, debug, function() return 0 end) |
|||
|
|||
end |
|||
|
|||
return function(ctx, mixc) |
|||
ctx[621] = function() |
|||
local globals = { err = nil } |
|||
|
|||
local program = get_prog() |
|||
local bfc = read_number_context(program, globals) |
|||
|
|||
local counter = 50000000 |
|||
|
|||
while bfc.retval == nil do |
|||
bfc:step(app) |
|||
if (counter == 0) then |
|||
counter = 50000000 |
|||
app.checkhangup() |
|||
if channel.HUNGUP:get() == "HUNGUP" then |
|||
app.verbose(3, "hung up on running program") |
|||
globals.err = "hung up" |
|||
end |
|||
end |
|||
if globals.err ~= nil then |
|||
return |
|||
end |
|||
counter = counter - 1 |
|||
end |
|||
|
|||
local tab = bfc.retval |
|||
|
|||
if tab.kind == "error" then |
|||
espeak("error " .. tab.value) |
|||
elseif tab.kind == "return" then |
|||
espeak("success") |
|||
else |
|||
espeak("unknown state") |
|||
end |
|||
|
|||
app.hangup() |
|||
end |
|||
end |
@ -0,0 +1,382 @@ |
|||
|
|||
local debugls = function(l) for k, v in pairs(l) do print("dbg: " .. tostring(k) .. " => " .. tostring(v)) end end |
|||
|
|||
-- Not portable |
|||
local separate_path = function(path) |
|||
for i = #path,1,-1 do |
|||
if string.sub(path, i, i) == "/" then |
|||
return { dir = string.sub(path, 1, i), file = string.sub(path, i + 1, #path) } |
|||
end |
|||
end |
|||
return { file = path } |
|||
end |
|||
|
|||
-- Not portable |
|||
local to_dir_name = function(s) |
|||
if string.sub(s, #s, #s) ~= "/" then |
|||
return s .. "/" |
|||
else |
|||
return s |
|||
end |
|||
end |
|||
|
|||
-- Not portable |
|||
local abs_filename = function(cwd, path) |
|||
if string.sub(path, 1, 1) == "/" then |
|||
return path |
|||
else |
|||
if string.sub(cwd, #cwd, #cwd) ~= "/" then |
|||
return to_dir_name(cwd) .. path |
|||
else |
|||
return to_dir_name(cwd) .. path |
|||
end |
|||
end |
|||
end |
|||
|
|||
-- Not portable |
|||
local normalize_abs_path = function(path, isdir) |
|||
local names = {} |
|||
for nm in string.gmatch(path, "[^/]+") do |
|||
names[#names + 1] = nm |
|||
end |
|||
|
|||
-- Normalize away `.` |
|||
for i = #names,1,-1 do |
|||
if names[i] == "." or names[i] == "" then |
|||
table.remove(names, i) |
|||
end |
|||
end |
|||
|
|||
-- Normalize away `..` |
|||
while names[1] == ".." do table.remove(names, 1) end |
|||
local c = true |
|||
while c do |
|||
c = false |
|||
for i = 1,(#names - 1) do |
|||
if names[i + 1] == ".." then |
|||
table.remove(names, i) |
|||
table.remove(names, i) |
|||
c = true |
|||
break |
|||
end |
|||
end |
|||
end |
|||
|
|||
if isdir then |
|||
return "/" .. table.concat(names, "/") .. "/" |
|||
else |
|||
return "/" .. table.concat(names, "/") |
|||
end |
|||
end |
|||
|
|||
local path_size = function(path) |
|||
local i = 0 |
|||
for _ in string.gmatch(path, "[^/]+") do |
|||
i = i + 1 |
|||
end |
|||
return i |
|||
end |
|||
|
|||
-- Not portable |
|||
local is_dir = function(filename) |
|||
local c = false |
|||
local p = io.popen("[ -d '" .. filename .. "' ] && echo ''") |
|||
for l in p:lines() do c = true end |
|||
p:close() |
|||
return c |
|||
end |
|||
|
|||
-- Not portable |
|||
local file_exists = function(filename) |
|||
local c = false |
|||
local p = io.popen("[ -e '" .. filename .. "' ] && echo ''") |
|||
for l in p:lines() do c = true end |
|||
p:close() |
|||
return c |
|||
end |
|||
|
|||
-- Not portable |
|||
local ls_dir = function(dirpath) |
|||
local t = {} |
|||
local p = io.popen("ls -A '" .. dirpath .. "'") |
|||
for l in p:lines() do t[#t + 1] = l end |
|||
p:close() |
|||
return t |
|||
end |
|||
|
|||
local read_manifest |
|||
read_manifest = function(filename, file_table, errout) |
|||
local parse_line = function(line, cwd) |
|||
local weight_specifier |
|||
local filepath |
|||
|
|||
for i = 1,#line do |
|||
if string.sub(line, i, i) == " " then |
|||
weight_specifier = string.sub(line, 1, i - 1) |
|||
filepath = string.sub(line, i + 1, #line) |
|||
break |
|||
end |
|||
end |
|||
|
|||
if weight_specifier == nil and filepath == nil then |
|||
return nil |
|||
end |
|||
|
|||
-- True if a category is to be weighted as a unit, thereby reducing the effective |
|||
-- weight of each of its entries. This flag is meant to be employed for other manifests. |
|||
local weight_whole_category = false |
|||
-- Indicates that the entry is a directory whose applicable files should be read in. |
|||
local directory = false |
|||
-- This indicates that the entry is a manifest to be read in. |
|||
local manifest = false |
|||
-- This is the level to recurse into directories or the `here` case. |
|||
-- `nil` indicates unbounded recursion. |
|||
local recursion_level = 0 |
|||
-- When `weight_whole_category` is on, this specifies how deeply the categorical |
|||
-- weighting will apply. Again, `nil` is unbounded. |
|||
local recursive_weighting_level = 0 |
|||
|
|||
local numstr = "" |
|||
|
|||
local symbol_actions = |
|||
{ |
|||
["#"] = function() weight_whole_category = true end, |
|||
["?"] = function() manifest = true end, |
|||
["/"] = function() if recursion_level ~= nil then recursion_level = recursion_level + 1 end end, |
|||
["*"] = function() recursion_level = nil end, |
|||
["$"] = function() if recursive_weighting_level ~= nil then recursive_weighting_level = recursive_weighting_level + 1 end end, |
|||
["%"] = function() recursive_weighting_level = nil end, |
|||
["0"] = true, |
|||
["1"] = true, |
|||
["2"] = true, |
|||
["3"] = true, |
|||
["4"] = true, |
|||
["5"] = true, |
|||
["6"] = true, |
|||
["7"] = true, |
|||
["8"] = true, |
|||
["9"] = true, |
|||
["-"] = true, |
|||
["."] = true, |
|||
["e"] = true, |
|||
} |
|||
|
|||
for i = 1,#weight_specifier do |
|||
local sym = string.sub(weight_specifier, i, i) |
|||
local action = symbol_actions[sym] |
|||
if action == true then |
|||
numstr = numstr .. sym |
|||
elseif action == nil then |
|||
else |
|||
action() |
|||
end |
|||
end |
|||
|
|||
local num = tonumber(numstr) |
|||
if num == nil then num = 1 end |
|||
|
|||
return |
|||
{ |
|||
weight = num, |
|||
manifest = manifest, |
|||
catweight = weight_whole_category, |
|||
directory = directory, |
|||
rclevel = recursion_level, |
|||
rcwlevel = recursive_weighting_level, |
|||
file = normalize_abs_path(abs_filename(cwd, filepath), false) |
|||
} |
|||
end |
|||
|
|||
local is_iv_name = function(s) return string.sub(s, -4, -1) == ".ivz" or string.sub(s, -3, -1) == ".iv" end |
|||
|
|||
local descend_dir |
|||
descend_dir = function(dirpath, file_table, total_weight, catweight, rclevel, rcwlevel, source) |
|||
local ftab = ls_dir(dirpath) |
|||
local nrcl |
|||
if rclevel == nil then nrcl = nil else nrcl = rclevel - 1 end |
|||
if catweight then |
|||
if rcwlevel == 0 then |
|||
local temp_table = {} |
|||
for _,en in pairs(ftab) do |
|||
local iv = normalize_abs_path(abs_filename(dirpath, en), false) |
|||
if is_dir(iv) and (rclevel == nil or rclevel > 0) then |
|||
descend_dir(to_dir_name(iv), temp_table, 1, false, nrcl, 0, source) |
|||
elseif is_iv_name(iv) then |
|||
temp_table[#temp_table + 1] = |
|||
{ |
|||
file = iv, |
|||
-- Will be overwritten by loop below anyway |
|||
} |
|||
end |
|||
end |
|||
for _,ent in pairs(temp_table) do |
|||
file_table[#file_table + 1] = |
|||
{ |
|||
file = ent.file, |
|||
weight = total_weight / #temp_table, |
|||
source = source |
|||
} |
|||
end |
|||
else |
|||
for _,en in pairs(ftab) do |
|||
local iv = normalize_abs_path(abs_filename(dirpath, en)) |
|||
if is_dir(iv) and (rclevel == nil or rclevel > 0) then |
|||
if rcwlevel == nil then |
|||
descend_dir(to_dir_name(iv), file_table, total_weight / #ftab, true, nrcl, nil, source) |
|||
else |
|||
descend_dir(to_dir_name(iv), file_table, total_weight / #ftab, true, nrcl, rcwlevel - 1, source) |
|||
end |
|||
elseif is_iv_name(iv) then |
|||
file_table[#file_table + 1] = |
|||
{ |
|||
file = iv, |
|||
weight = total_weight / #ftab, |
|||
source = source |
|||
} |
|||
end |
|||
end |
|||
end |
|||
return total_weight |
|||
else |
|||
local twc = 0 |
|||
for _,en in pairs(ftab) do |
|||
local iv = normalize_abs_path(abs_filename(dirpath, en)) |
|||
if is_dir(iv) and (rclevel == nil or rclevel > 0) then |
|||
descend_dir(to_dir_name(iv), file_table, total_weight, false, nrcl, 0, source) |
|||
elseif is_iv_name(iv) then |
|||
twc = twc + total_weight |
|||
file_table[#file_table + 1] = |
|||
{ |
|||
file = iv, |
|||
weight = total_weight, |
|||
source = source |
|||
} |
|||
end |
|||
end |
|||
return twc |
|||
end |
|||
end |
|||
|
|||
if filename == nil then return nil end |
|||
|
|||
local mf = io.open(filename, "r") |
|||
if not mf then errout("Could not open manifest " .. filename) return nil end |
|||
local total_weight = 0 |
|||
|
|||
for line in mf:lines() do |
|||
local entry = parse_line(line, separate_path(filename).dir) |
|||
if entry == nil then goto endloop end |
|||
|
|||
if entry.manifest then |
|||
if not file_exists(entry.file) or is_dir(entry.file) then |
|||
errout("warning: file " .. entry.file .. " is not a normal file") |
|||
end |
|||
local temp_table = {} |
|||
local tw = read_manifest(entry.file, temp_table, errout) |
|||
if entry.catweight then |
|||
total_weight = total_weight + entry.weight |
|||
for _,ent in pairs(temp_table) do |
|||
file_table[#file_table + 1] = |
|||
{ |
|||
file = ent.file, |
|||
weight = entry.weight * ent.weight / tw, |
|||
source = ent.source, |
|||
} |
|||
end |
|||
else |
|||
for _,ent in pairs(temp_table) do |
|||
total_weight = total_weight + entry.weight * ent.weight |
|||
file_table[#file_table + 1] = |
|||
{ |
|||
file = ent.file, |
|||
weight = entry.weight * ent.weight, |
|||
source = ent.source, |
|||
} |
|||
end |
|||
end |
|||
else |
|||
if not file_exists(entry.file) then |
|||
errout("warning: file " .. entry.file .. " does not exist") |
|||
end |
|||
if is_dir(entry.file) then |
|||
total_weight = total_weight + descend_dir(to_dir_name(entry.file), file_table, entry.weight, entry.catweight, entry.rclevel, entry.rcwlevel, { file = entry.file, manifest = normalize_abs_path(filename) }) |
|||
else |
|||
total_weight = total_weight + entry.weight |
|||
file_table[#file_table + 1] = |
|||
{ |
|||
file = entry.file, |
|||
weight = entry.weight, |
|||
source = { file = entry.file, manifest = normalize_abs_path(filename) } |
|||
} |
|||
end |
|||
end |
|||
|
|||
::endloop:: |
|||
end |
|||
|
|||
mf:close() |
|||
|
|||
return total_weight |
|||
end |
|||
|
|||
local assemble_weights = function(entries, errout) |
|||
local ivs = {} |
|||
|
|||
for _, ent in pairs(entries) do |
|||
if ivs[ent.file] ~= nil then |
|||
local sza = path_size(ivs[ent.file].source.file) |
|||
local szb = path_size(ent.source.file) |
|||
if sza < szb then |
|||
ivs[ent.file] = { weight = ent.weight, source = ent.source } |
|||
elseif sza == szb then |
|||
local namea = ivs[ent.file].source.manifest |
|||
local nameb = ent.source.manifest |
|||
if namea == nameb then |
|||
errout("warning: two conflicting weights for " .. ent.file .. " in " .. namea) |
|||
else |
|||
errout("warning: two conflicting weights for " .. ent.file .. " in " .. namea .. " and " .. nameb) |
|||
end |
|||
end |
|||
else |
|||
ivs[ent.file] = { weight = ent.weight, source = ent.source } |
|||
end |
|||
end |
|||
|
|||
return ivs |
|||
end |
|||
|
|||
local function usage() |
|||
print("usage: <this program> <input manifest> <output table>") |
|||
end |
|||
|
|||
if arg[1] == nil or arg[2] == nil then |
|||
usage() |
|||
return |
|||
end |
|||
|
|||
local taboutf = io.open(arg[2], "w") |
|||
if taboutf == nil then |
|||
print("Could not open output file") |
|||
return |
|||
end |
|||
|
|||
local tab = {} |
|||
|
|||
read_manifest(arg[1], tab, function(s) print(s) end) |
|||
|
|||
local weightmap = assemble_weights(tab, function(s) print(s) end) |
|||
|
|||
local cumweights = {} |
|||
local cum = 0.0 |
|||
|
|||
for file, wt in pairs(weightmap) do |
|||
cum = cum + wt.weight |
|||
table.insert(cumweights, { cum = cum, file = file, wt = wt }) |
|||
end |
|||
|
|||
for idx, ent in ipairs(cumweights) do |
|||
taboutf:write(tostring(ent.cum) .. " : " .. ent.file .. "\n") |
|||
end |
|||
|
|||
taboutf:close() |
|||
|
@ -0,0 +1,61 @@ |
|||
|
|||
local function read_table(filename, file_table, errout) |
|||
local function parse_line(line, file_table, errout) |
|||
local s, e = string.find(line, " : ") |
|||
if s == nil or e == nil then |
|||
errout("error: bad line") |
|||
return |
|||
end |
|||
local cum = tonumber(string.sub(line, 1, s - 1)) |
|||
local file = string.sub(line, e + 1) |
|||
table.insert(file_table, { cum = cum, file = file }) |
|||
end |
|||
|
|||
local tabf = io.open(filename, "r") |
|||
if tabf == nil then |
|||
errout("could not open table file " .. filename) |
|||
return |
|||
end |
|||
|
|||
for line in tabf:lines() do |
|||
parse_line(line, file_table, errout) |
|||
end |
|||
|
|||
io.close(tabf) |
|||
end |
|||
|
|||
local function search_table(file_table, cum) |
|||
local s = 1 |
|||
local e = #file_table - 1 |
|||
while true do |
|||
if s >= e then |
|||
return s |
|||
end |
|||
local sidx = math.floor((s + e) / 2) |
|||
if cum < file_table[sidx].cum then |
|||
e = sidx |
|||
else |
|||
s = sidx + 1 |
|||
end |
|||
end |
|||
end |
|||
|
|||
local ftab = {} |
|||
|
|||
read_table("outtab.txt", ftab, function(em) print(em) end) |
|||
|
|||
--for idx, ent in ipairs(ftab) do |
|||
-- print(tostring(idx) .. " cwgt(" .. tostring(ent.file) .. ") = " .. tostring(ent.cum)) |
|||
--end |
|||
|
|||
local uw = ftab[#ftab - 1].cum |
|||
|
|||
math.randomseed(os.time()) |
|||
for i=1,100 do |
|||
local eidx = search_table(ftab, math.random() * uw) |
|||
local fname = ftab[eidx].file |
|||
print(fname) |
|||
end |
|||
|
|||
return { read_table = read_table, search_table = search_table } |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue