mirror of
https://github.com/notwa/mm
synced 2024-11-10 11:39:04 -08:00
add missing files for lips
This commit is contained in:
parent
bef45dc1cd
commit
449c021110
4 changed files with 342 additions and 5 deletions
|
@ -236,10 +236,14 @@ local time_menu = oot and Menu{
|
|||
Oneshot("Set Day to Second", Setter{[addrs.day]=2, [addrs.days_elapsed]=2}),
|
||||
Oneshot("Set Day to Final", Setter{[addrs.day]=3, [addrs.days_elapsed]=3}),
|
||||
Oneshot("Set Day to New", Setter{[addrs.day]=4, [addrs.days_elapsed]=4}),
|
||||
Oneshot("Set Time to 06:00", Setter{[addrs.time]=0x4000}),
|
||||
Oneshot("Set Time to 12:00", Setter{[addrs.time]=0x8000}),
|
||||
Oneshot("Set Time to 18:00", Setter{[addrs.time]=0xC000}),
|
||||
Oneshot("Set Time to 00:00", Setter{[addrs.time]=0x0000}),
|
||||
Oneshot("Set Time to 00:00", Setter{[addrs.time]=0x0000, [addrs.day_night]=1}),
|
||||
Oneshot("Set Time to 03:00", Setter{[addrs.time]=0x2000, [addrs.day_night]=1}),
|
||||
Oneshot("Set Time to 06:00", Setter{[addrs.time]=0x4000, [addrs.day_night]=0}),
|
||||
Oneshot("Set Time to 09:00", Setter{[addrs.time]=0x6000, [addrs.day_night]=0}),
|
||||
Oneshot("Set Time to 12:00", Setter{[addrs.time]=0x8000, [addrs.day_night]=0}),
|
||||
Oneshot("Set Time to 15:00", Setter{[addrs.time]=0xA000, [addrs.day_night]=0}),
|
||||
Oneshot("Set Time to 18:00", Setter{[addrs.time]=0xC000, [addrs.day_night]=1}),
|
||||
Oneshot("Set Time to 21:00", Setter{[addrs.time]=0xE000, [addrs.day_night]=1}),
|
||||
Text(""),
|
||||
Oneshot("Time flow: Fast", Setter{[addrs.time_speed]=2}),
|
||||
Oneshot("Time flow: Normal", Setter{[addrs.time_speed]=0}),
|
||||
|
|
|
@ -166,7 +166,8 @@ local asms = {
|
|||
-- ['O EUDB MQ'] = {'widescreen-inline.asm', true},
|
||||
['O EUDB MQ'] = {'print.asm'},
|
||||
|
||||
['M US10'] = {'beta.asm'},
|
||||
-- ['M US10'] = {'beta.asm'},
|
||||
['M US10'] = {'spawn mm.asm'},
|
||||
['M JP10'] = {'spawn mm early.asm'},
|
||||
}
|
||||
|
||||
|
|
310
Lua/lib/lips/Expression.lua
Normal file
310
Lua/lib/lips/Expression.lua
Normal file
|
@ -0,0 +1,310 @@
|
|||
local insert = table.insert
|
||||
|
||||
local path = string.gsub(..., "[^.]+$", "")
|
||||
local Base = require(path.."Base")
|
||||
|
||||
local Expression = Base:extend()
|
||||
|
||||
Expression.precedence = {
|
||||
-- python-ish precedence
|
||||
[","] = -1,
|
||||
["or"] = 0,
|
||||
["||"] = 0,
|
||||
["xor"] = 1,
|
||||
["and"] = 2,
|
||||
["&&"] = 2,
|
||||
["unary not"] = 3,
|
||||
["=="] = 5,
|
||||
["!="] = 5,
|
||||
["<"] = 5,
|
||||
[">"] = 5,
|
||||
["<="] = 5,
|
||||
[">="] = 5,
|
||||
["|"] = 10,
|
||||
["^"] = 11,
|
||||
["&"] = 12,
|
||||
["<<"] = 13,
|
||||
[">>"] = 13,
|
||||
["+"] = 20,
|
||||
["-"] = 20,
|
||||
["*"] = 21,
|
||||
["/"] = 21,
|
||||
["//"] = 21,
|
||||
["%"] = 21,
|
||||
["%%"] = 21,
|
||||
["unary !"] = 30,
|
||||
["unary ~"] = 30,
|
||||
["unary +"] = 30,
|
||||
["unary -"] = 30,
|
||||
-- note: precedence of 40 is hardcoded for right-left association
|
||||
-- TODO: also hardcode unary handling on right-hand side of operator
|
||||
["**"] = 40,
|
||||
}
|
||||
|
||||
Expression.unary_ops = {
|
||||
["not"] = function(a) return a == 0 end,
|
||||
["!"] = function(a) return a == 0 end,
|
||||
-- ["~"] = function(a) return F(~I(a)) end,
|
||||
["+"] = function(a) return a end,
|
||||
["-"] = function(a) return -a end,
|
||||
}
|
||||
|
||||
Expression.binary_ops = {
|
||||
[","] = function(a, b) return b end,
|
||||
["or"] = function(a, b) return a or b end,
|
||||
["||"] = function(a, b) return a or b end,
|
||||
["xor"] = function(a, b) return (a or b) and not (a and b) end,
|
||||
["and"] = function(a, b) return a and b end,
|
||||
["&&"] = function(a, b) return a and b end,
|
||||
["=="] = function(a, b) return a == b end,
|
||||
["!="] = function(a, b) return a ~= b end,
|
||||
["<"] = function(a, b) return a < b end,
|
||||
[">"] = function(a, b) return a > b end,
|
||||
["<="] = function(a, b) return a <= b end,
|
||||
[">="] = function(a, b) return a >= b end,
|
||||
-- ["|"] = function(a, b) return F(I(a) | I(b)) end,
|
||||
-- ["^"] = function(a, b) return F(I(a) ^ I(b)) end,
|
||||
-- ["&"] = function(a, b) return F(I(a) & I(b)) end,
|
||||
-- ["<<"] = function(a, b) return F(I(a) << I(b)) end,
|
||||
-- [">>"] = function(a, b) return F(I(a) >> I(b)) end,
|
||||
["+"] = function(a, b) return a + b end,
|
||||
["-"] = function(a, b) return a - b end,
|
||||
["*"] = function(a, b) return a * b end,
|
||||
["/"] = function(a, b) return a / b end,
|
||||
-- ["//"] = function(a, b) return trunc(a / trunc(b)) end,
|
||||
-- ["%"] = function(a, b) return fmod(a, b) end,
|
||||
-- ["%%"] = function(a, b) return trunc(fmod(a, trunc(b))) end,
|
||||
["**"] = function(a, b) return a^b end,
|
||||
}
|
||||
|
||||
local operators = {}
|
||||
local operators_maxlen = 0
|
||||
do
|
||||
for k, v in pairs(Expression.precedence) do
|
||||
if operators[#k] == nil then
|
||||
operators[#k] = {}
|
||||
end
|
||||
local op = k:find('^unary ') and k:sub(#'unary ' + 1) or k
|
||||
insert(operators[#k], op)
|
||||
if #k > operators_maxlen then
|
||||
operators_maxlen = #k
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function match_operator(str)
|
||||
-- returns the operator at the beginning of a string, or nil
|
||||
for i=operators_maxlen, 1, -1 do
|
||||
if operators[i] ~= nil then
|
||||
local substr = str:sub(1, i)
|
||||
for _, op in ipairs(operators[i]) do
|
||||
if substr == op then
|
||||
return substr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Expression:lex1(str, tokens)
|
||||
local pos = 1
|
||||
local rest = str
|
||||
local function consume(n)
|
||||
pos = pos + n
|
||||
rest = rest:sub(n + 1)
|
||||
end
|
||||
|
||||
local considered = ''
|
||||
local function consider(pattern)
|
||||
local start, stop = rest:find('^'..pattern)
|
||||
if start == nil then
|
||||
considered = ''
|
||||
return false
|
||||
end
|
||||
considered = rest:sub(start, stop)
|
||||
return true
|
||||
end
|
||||
|
||||
local function consider_operator()
|
||||
local op = match_operator(rest)
|
||||
if op == nil then
|
||||
considered = ''
|
||||
return false
|
||||
end
|
||||
considered = op
|
||||
return true
|
||||
end
|
||||
|
||||
while pos <= #str do
|
||||
local old_pos = pos
|
||||
local here = " (#"..tostring(pos)..")"
|
||||
if consider(' +') then
|
||||
consume(#considered)
|
||||
elseif consider('[0-9.]') then
|
||||
local num
|
||||
if consider('((0|[1-9][0-9]*)%.[0-9]*|%.[0-9]+)(e0|e[1-9][0-9]*)?') then
|
||||
num = tonumber(considered)
|
||||
elseif consider('(0|[1-9][0-9]*)e(0|[1-9][0-9]*)') then
|
||||
num = tonumber(considered)
|
||||
elseif consider('[0-1]+b') then
|
||||
num = tonumber(considered, 2)
|
||||
elseif consider('0x[0-9A-Fa-f]+') then
|
||||
num = tonumber(considered, 16)
|
||||
elseif consider('0[0-7]+') then
|
||||
num = tonumber(considered, 8)
|
||||
elseif consider('[1-9][0-9]*') then
|
||||
num = tonumber(considered)
|
||||
end
|
||||
if num == nil then
|
||||
return "invalid number"..here
|
||||
end
|
||||
insert(tokens, {type='number', value=num})
|
||||
consume(#considered)
|
||||
elseif consider('[(]') then
|
||||
insert(tokens, {type='opening', value=considered})
|
||||
consume(#considered)
|
||||
elseif consider('[)]') then
|
||||
insert(tokens, {type='closing', value=considered})
|
||||
consume(#considered)
|
||||
elseif consider_operator() then
|
||||
insert(tokens, {type='operator', value=considered})
|
||||
consume(#considered)
|
||||
else
|
||||
local chr = rest:sub(1, 1)
|
||||
return "unexpected character '"..chr.."'"..here
|
||||
end
|
||||
if pos == old_pos then
|
||||
error("Internal Error: expression parser is stuck")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Expression:lex2(tokens)
|
||||
-- detect unary operators
|
||||
-- TODO: this is probably not the best way to do this
|
||||
local was_numeric = false
|
||||
local was_closing = false
|
||||
for i, t in ipairs(tokens) do
|
||||
if t.type == "operator" and not was_numeric and not was_closing then
|
||||
t.type = "unary";
|
||||
end
|
||||
was_numeric = t.type == 'number'
|
||||
was_closing = t.type == 'closing'
|
||||
end
|
||||
end
|
||||
|
||||
function Expression:lex(str)
|
||||
local tokens = {}
|
||||
err = self:lex1(str, tokens)
|
||||
if err then return tokens, err end
|
||||
err = self:lex2(tokens)
|
||||
return tokens, err
|
||||
end
|
||||
|
||||
function Expression:shunt(tokens)
|
||||
-- shunting yard algorithm
|
||||
local shunted = {}
|
||||
local stack = {}
|
||||
|
||||
local operator_types = {
|
||||
unary = true,
|
||||
operator = true,
|
||||
}
|
||||
|
||||
for _, t in ipairs(tokens) do
|
||||
if t.type == 'number' then
|
||||
insert(shunted, t)
|
||||
elseif t.type == 'opening' then
|
||||
insert(stack, t)
|
||||
elseif t.type == 'closing' then
|
||||
while #stack > 0 and stack[#stack].type ~= 'opening' do
|
||||
insert(shunted, stack[#stack])
|
||||
stack[#stack] = nil
|
||||
end
|
||||
if #stack == 0 then return shunted, 'missing opening parenthesis' end
|
||||
stack[#stack] = nil
|
||||
elseif t.type == 'operator' or t.type == 'unary' then
|
||||
local fullname = t.type == 'unary' and 'unary '..t.value or t.value
|
||||
local pre = self.precedence[fullname]
|
||||
if pre == nil then return shunted, 'unknown operator' end
|
||||
if pre == 40 then pre = pre + 1 end -- right-associative hack
|
||||
while #stack > 0 do
|
||||
local tail = stack[#stack]
|
||||
if not operator_types[tail.type] then break end
|
||||
local dpre = pre - self.precedence[tail.value]
|
||||
if dpre > 0 then break end
|
||||
insert(shunted, tail)
|
||||
stack[#stack] = nil
|
||||
end
|
||||
insert(stack, t)
|
||||
else
|
||||
error('Internal Error: unknown type of expression token')
|
||||
end
|
||||
end
|
||||
|
||||
while #stack > 0 do
|
||||
local t = stack[#stack]
|
||||
if t.type == 'opening' then return shunted, 'missing closing parenthesis' end
|
||||
insert(shunted, t)
|
||||
stack[#stack] = nil
|
||||
end
|
||||
|
||||
return shunted, nil
|
||||
end
|
||||
|
||||
function Expression:parse(str)
|
||||
local tokens, err = self:lex(str)
|
||||
if err then return tokens, err end
|
||||
tokens, err = self:shunt(tokens)
|
||||
--for i, v in ipairs(tokens) do print(i, v.type, v.value) end
|
||||
return tokens, err
|
||||
end
|
||||
|
||||
function Expression:eval(tokens_or_str)
|
||||
local tokens, err
|
||||
if type(tokens_or_str) == 'string' then
|
||||
tokens, err = self:parse(tokens_or_str)
|
||||
if err then return 0, err end
|
||||
elseif type(tokens_or_str) == 'table' then
|
||||
tokens = tokens_or_str
|
||||
else
|
||||
return 0, "eval(): argument is neither token table nor string"
|
||||
end
|
||||
|
||||
local stack = {}
|
||||
local popped
|
||||
local function pop()
|
||||
if #stack == 0 then return true end
|
||||
popped = stack[#stack]
|
||||
stack[#stack] = nil
|
||||
return false
|
||||
end
|
||||
|
||||
for i, t in ipairs(tokens) do
|
||||
if t.type == 'number' then
|
||||
insert(stack, t.value)
|
||||
elseif t.type == 'unary' then
|
||||
if pop() then return 0, "missing arguments for unary" end
|
||||
local f = self.unary_ops[t.value]
|
||||
if f == nil then return 0, "unknown unary" end
|
||||
insert(stack, f(popped))
|
||||
elseif t.type == 'operator' then
|
||||
if pop() then return 0, "missing arguments for operator" end
|
||||
local b = popped
|
||||
if pop() then return 0, "missing arguments for operator" end
|
||||
local a = popped
|
||||
local f = self.binary_ops[t.value]
|
||||
if f == nil then return 0, "unknown operator" end
|
||||
insert(stack, f(a, b))
|
||||
else
|
||||
return 0, "eval(): unknown token"
|
||||
end
|
||||
end
|
||||
|
||||
if #stack > 1 then return 0, "too many arguments" end
|
||||
if #stack == 0 then return 0, "no arguments" end
|
||||
|
||||
return stack[1], nil
|
||||
end
|
||||
|
||||
return Expression
|
22
Lua/lib/lips/LICENSE
Normal file
22
Lua/lib/lips/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
Copyright (C) 2015,2016 Connor Olding
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
Loading…
Reference in a new issue