mirror of
https://github.com/notwa/mm
synced 2024-11-05 06:39:02 -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 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 Final", Setter{[addrs.day]=3, [addrs.days_elapsed]=3}),
|
||||||
Oneshot("Set Day to New", Setter{[addrs.day]=4, [addrs.days_elapsed]=4}),
|
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 00:00", Setter{[addrs.time]=0x0000, [addrs.day_night]=1}),
|
||||||
Oneshot("Set Time to 12:00", Setter{[addrs.time]=0x8000}),
|
Oneshot("Set Time to 03:00", Setter{[addrs.time]=0x2000, [addrs.day_night]=1}),
|
||||||
Oneshot("Set Time to 18:00", Setter{[addrs.time]=0xC000}),
|
Oneshot("Set Time to 06:00", Setter{[addrs.time]=0x4000, [addrs.day_night]=0}),
|
||||||
Oneshot("Set Time to 00:00", Setter{[addrs.time]=0x0000}),
|
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(""),
|
Text(""),
|
||||||
Oneshot("Time flow: Fast", Setter{[addrs.time_speed]=2}),
|
Oneshot("Time flow: Fast", Setter{[addrs.time_speed]=2}),
|
||||||
Oneshot("Time flow: Normal", Setter{[addrs.time_speed]=0}),
|
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'] = {'widescreen-inline.asm', true},
|
||||||
['O EUDB MQ'] = {'print.asm'},
|
['O EUDB MQ'] = {'print.asm'},
|
||||||
|
|
||||||
['M US10'] = {'beta.asm'},
|
-- ['M US10'] = {'beta.asm'},
|
||||||
|
['M US10'] = {'spawn mm.asm'},
|
||||||
['M JP10'] = {'spawn mm early.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