User:XFire35/auo.lua

From Esolang
Revision as of 10:12, 25 October 2009 by XFire35 (talk | contribs) (New page: <pre> #!/usr/bin/env lua --[[ Copyright (c) 2009, Curt Strangward Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereb...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
#!/usr/bin/env lua

--[[
    Copyright (c) 2009, Curt Strangward
    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted, provided that the above
    copyright notice and this permission notice appear in all copies.


    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
    DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
    RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
    CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
    CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
]]--

    _s          =   {}  -- Stack
    _v          =   {}  -- Variable Stack
    _j          =   {}  -- Jump Stack
    _c          =   {}  -- Code Stack
    _t          =   {}  -- Temporary Array
    _l          =   {}  -- Loop Array - Used in Control Flow Statements

---------------------------------------------------------------------------------------------
--  Language Support Functions

    function print(text)    -- Modifies lua's print to make it look nicer
        if text ~= nil then io.write ( ":: "..text.."\n" );
        else end
    end

    function pA(array)      -- Prints the array
        for k, v in pairs(array) do
            print(k..": "..array[k]);
        end
    end

    function c_v(var)       -- Checks variable
        if _v[var] then
            if type(_v[var]) == "string" then
                return("'".._v[var].."'")
            else
                return(_v[var])
            end
        else
            print("Unidentified Value: "..var)
        end
    end

    function c_vB(var)       -- Checks variable B version
        if _v[var] then
            return(_v[var])
        else
            print("Unidentified Value: "..var)
        end
    end

    function v_m(_cT)
        if string.match(_cT, "%$[%w+%_]+") then
            _cT = string.gsub(_cT, "%$([%w+%_]+)", c_v)
        end
        return(_cT)
    end

---------------------------------------------------------------------------------------------
--  Language's Stack Functions

    function s_push(value)              -- Push value to _s
        table.insert(_s, value)
    end

    function s_pop()                    -- Retrieve top _s item
        if table.getn(_s) == 0 then return ("0")
        else
            return(table.remove(_s))
        end
    end

    function s_del()                    -- Remove top item from stack
        s_pop()
    end

    function s_mer()                  -- Merge top two items on stack
        local a, b = s_pop(), s_pop()
        s_push(tostring(a)..tostring(b))
    end

    function s_dup()                    -- Duplicate top item on _s
        if table.getn(_s) == 0 then e("Stack","0")
        else
            local a = s_pop()
            s_push(a); s_push(a);
        end
    end

    function s_exh(value)               -- Exchanges top two _s items
        local a, b = s_pop(), s_pop()
        s_push(a); s_push(b);
    end

    function s_clear()                   -- Clear the stack
        _s = {}
    end

---------------------------------------------------------------------------------------------
--  Language's Functions

    function m_add(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            s_push(x+y)
        else print("Malformed Variables") end
    end

    function m_sub(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            s_push(x-y)
        else print("Malformed Variables") end
    end

    function m_mul(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            s_push(x*y)
        else print("Malformed Variables") end
    end

    function m_div(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            s_push(x/y)
        else print("Malformed Variables") end
    end


    function q_equ(x,y)
        if x ~= "" or nil and y ~= "" or nil then
            if x == y then s_push('true') else s_push('false') end
        end
    end

    function q_neq(x,y)
        if x ~= "" or nil and y ~= "" or nil then
            if x ~= y then s_push('true') else s_push('false') end
        end
    end

    function q_lss(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            if x < y then s_push('true') else s_push('false') end
        else print("Malformed Variables") end
    end

    function q_els(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            if x <= y then s_push('true') else s_push('false') end
        else print("Malformed Variables") end
    end

    function q_grt(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            if x > y then s_push('true') else s_push('false') end
        else print("Malformed Variables") end
    end

    function q_egr(x,y)
        local x, y = tonumber(x), tonumber(y)
        if type(x) == "number" and type(y) == "number" then
            if x >= y then s_push('true') else s_push('false') end
        else print("Malformed Variables") end
    end

    function t_len(x)
        if x ~= "" or nil then
            s_push(string.len(tostring(x)))
        end
    end

    function t_add(x,y)
        s_push(x..y)
    end

    function t_div(x,n)

        local _t, _t2, n = {}, {}, tonumber(n)

        for m in string.gfind(x, "[%w%p%s]") do
            table.insert(_t, m)
        end
        if n > table.getn(_t) then
            print("Error: Value exceeds string length")
        else
            for i = n, table.getn(_t),1 do
                table.insert(_t2, _t[i])
                _t[i] = nil
            end
            _t, _t2 = table.concat(_t,""), table.concat(_t2,"")
            s_push(_t); s_push(_t2)
        end
    end

    function i_prt(text)
        if text ~= nil then io.write ( ":> "..text.."\n" );
        else end
    end

---------------------------------------------------------------------------------------------
--  Main Language Parser, Causes everything to be run

    function process(t)

        for token = 1, table.getn(t) do
            local _cT = t[token]

            -- Conditional Statements

            -- c.i:[%true],[%false] > q.g:$x,10
            if string.match(_cT, "c%.i%:%[%%([%w%_]+)%],%[%%([%w%_]+)%][%s]*%>[%s]*%a%.%a%:([%w%p]+)%,([%w%p]+)") then

                _cT = string.gsub(_cT, "[%w%p%s]+(%a%.%a%:[%w%p]+%,[%w%p]+)", function(w) table.insert(_l,w); process(_l) end)
                _l = {}
                if s_pop() == "true" then
                    _cT = string.gsub(_cT, "c%.i%:%[(%%[%w%_]+)%][%w%p%s]+", function(w) table.insert(_l,w); process(_l) end)

                elseif s_pop() == "false" then
                    _cT = string.gsub(_cT, "c%.i%:[%w%p%s]+,%[(%%[%w%_]+)%][%w%p%s]", function(w) table.insert(_l,w); process(_l) end)

                end
                _l = {}

            -- c.f:[update],[%body] > q.g:$x,10
            elseif string.match(_cT, "c%.f%:%[%a%.%a%:$[%w%_]+%,[%w%p]+%],%[%%[%w%_]+%][%s]*%>[%s]*%a%.%a%:[%w%p]+%,[%w%p]+") then

                local var = ""
                _cT = string.gsub(_cT, "[%w%p%s]+%>[%s]*(%a%.%a%:[%w%p]+%,[%w%p]+)", function(w) table.insert(_l,w); end)   -- Argument
                _cT = string.gsub(_cT, "c%.f%:[%w%p%s]+,%[(%%[%w%_]+)%][%w%p%s]+", function(w) table.insert(_l,w); end)     -- Body
                _cT = string.gsub(_cT, "c%.f%:%[(%a%.%a%:$[%w%_]+%,[%w%p]+)%][%w%p]+", function(w) table.insert(_l,w); end) -- Change
                _cT = string.gsub(_cT, "c%.f%:%[%a%.%a%:$([%w%_]+)%,[%w%p]+%][%w%p%s]", function(w) if _v[w] then var = w end end)

                while true do
                    process(_l)
                    _v[var] = s_pop()
                    if s_pop() == "false" then  break end
                end
                _l = {}

            -- c.w:[update],[%body] > q.g:$x,10
            elseif string.match(_cT, "c%.w%:%[%%([%w%_]+)%][%s]*%>[%s]*%a%.%a%:([%w%p]+)%,([%w%p]+)") then

                _cT = string.gsub(_cT, "[%w%p%s]+%>[%s]*(%a%.%a%:[%w%p]+%,[%w%p]+)", function(w) table.insert(_l,w) end)
                _cT = string.gsub(_cT, "c%.w%:%[(%%[%w%_]+)%][%w%p%s]", function(w) table.insert(_l,w) end)

                while true do
                    process(_l)
                    if s_pop() == "false" then  break end
                end
                _l = {}

            -- %foo             -- Runs function 'foo'
            elseif string.match(_cT, "^%%([%w%_]+)") then

                _cT = string.gsub(_cT, "%%([%w%_]+)", function(w) if _j[w] then process(_j[w]); end end)

            end

            -- Math Functions

            -- m.a:x,y  - Add x and y
            if string.match(_cT, "m%.a%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "m%.a%:(%w+),(%w+)", m_add)

            -- m.s:x,y  - Add x and y
            elseif string.match(_cT, "m%.s%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "m%.s%:(%w+),(%w+)", m_sub)

            -- m.m:x,y  - Add x and y
            elseif string.match(_cT, "m%.m%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "m%.m%:(%w+),(%w+)", m_mul)

            -- m.d:x,y  - Add x and y
            elseif string.match(_cT, "m%.d%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "m%.d%:(%w+),(%w+)", m_div)

            -- Comparison Functions

            -- q.e:x,y             Equal?
            elseif string.match(_cT, "q%.e%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "q%.e%:([%w%p%s]+),([%w%p%s]+)", q_equ)

            -- q.n:x,y             Not equal?
            elseif string.match(_cT, "q%.n%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "q%.n%:%'?([%w%p%s]+)%'?,%'?([%w%p%s]+)%'?", q_neq)

            -- q.l:x,y             x less than y
            elseif string.match(_cT, "q%.l%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "q%.l%:(%w+),(%w+)", q_lss)

            -- q.s:x,y             x less than, equal to y
            elseif string.match(_cT, "q%.s%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "q%.a%:(%w+),(%w+)", q_els)

            -- q.g:x,y             x greater than y
            elseif string.match(_cT, "q%.g%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "q%.g%:(%w+),(%w+)", q_grt)

            -- q.r:x,y             x greater than, equal to y
            elseif string.match(_cT, "q%.r%:(%-?[%$%_%w%.?]+),(%-?[%$%_%w%.?]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "q%.r%:(%w+),(%w+)", q_egr)

            end

            -- String Functions

            -- s.l:x    - Length of string x
            if string.match(_cT, "s%.l%:([%w%p]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "s%.l%:%'([%w%s%p]+)%'", t_len)

            -- s.a:x,y    - Add strings x and y together
            elseif string.match(_cT, "s%.a%:([%w%p]+),([%w%p]+)") then
                _cT = v_m(_cT)
                _cT = string.gsub(_cT, "s%.a%:%'([%w%s%p]+)%','([%w%s%p]+)%'", t_add)

            -- s.s:x,n    - Split string x at position n
            elseif string.match(_cT, "s%.s%:([%w%p]+),([%w%p]+)") then
                _cT = v_m(_cT)
                if string.match(_cT, "s%.s%:%'([%w%s%p]+)%',([%d]+)") then
                    _cT = string.gsub(_cT, "s%.s%:%'([%w%s%p]+)%',([%d]+)", function(w,x) t_div(w,x) end)
                end

            end

            -- Stack Functions

            -- @    Pushes value to stack
            if string.match(_cT, "%'?([%$%_%w]+)%'?[%s]*%>[%s]*%@") then

                _cT = v_m(_cT)
                if string.match(_cT, "(%-?[%d%.?]+)[%s]*%>[%s]*%@") then
                    _cT = string.gsub(_cT, "(%-?[%d%.?]+)[%s]*%>[%s]*%@", function(w) s_push(tonumber(w)) end)

                elseif string.match(_cT, "%'([%w%s%p]+)%'[%s]*%>[%s]*%@") then
                    _cT = string.gsub(_cT, "%'([%w%s%p]+)%'[%s]*%>[%s]*%@", function(w) s_push(tostring(w)) end)
                end

            -- <@   Pops value from stack
            elseif string.match(_cT, "%<%@") then
                local var = s_pop()
                if type(var) == "number" then _cT = string.gsub(_cT, "%<%@", var)
                else _cT = string.gsub(_cT, "%<%@", "'"..var.."'") end

            -- -@   Disgards top item on stack
            elseif string.match(_cT, "%-%@") then
                s_del()

            -- *@    Duplicate top item on stack
            elseif string.match(_cT, "%*%@") then
                s_dup()

            -- +@   Merges the top two items on stack
            elseif string.match(_cT, "%+%@") then
                s_mer()

            -- ~@   Disgards top item on stack
            elseif string.match(_cT, "%~%@") then
                s_exh()

            -- /@   Clears the stack
            elseif string.match(_cT, "%@") then
                s_clear()

            end

            -- Variable Declaration Functions

            -- 5 > $a
            if string.match(_cT, "(%-?[%d%.?]+)[%s]*%>[%s]*%$([%w%_]+)") then
                _cT = string.gsub(_cT, "(%-?[%d%.?]+)[%s]*%>[%s]*%$([%w%_]+)", function(w,x) _v[x] = tonumber(w) end)

            -- 'foo' > $bar
            elseif string.match(_cT, "%'([%w%s%p]+)%'[%s]*%>[%s]*%$([%w%_]+)") then
                _cT = string.gsub(_cT, "%'([%w%s%p]+)%'[%s]*%>[%s]*%$([%w%_]+)", function(w,x) _v[x] = tostring(w) end)

            -- $nil > $foo, Clears value $foo
            elseif string.match(_cT, "%$nil[%s]*%>[%s]*%$([%w%_]+)") then
                _cT = string.gsub(_cT, "%$nil[%s]*%>[%s]*%$([%w%_]+)", function(w) _v[w] = nil end)

            -- $foo > $bar
            elseif string.match(_cT, "%$([%w%_]+)[%s]*%>[%s]*%$([%w%_]+)") then
                _cT = string.gsub(_cT, "%$([%w%_]+)[%s]*%>[%s]*%$([%w%_]+)", function(w,x) if _v[w] then _v[x] = c_v(w) end end)

            end

            -- Input/Output Functions

            -- i.o:['Message']  -- Writes message
            if string.match(_cT, "i%.o%:%[%'[%w+%s+%p+]+%'%]") then

                if string.match(_cT, "%$[%w+%_]+") then
                    _cT = string.gsub(_cT, "%$([%w+%_]+)", c_vB)
                end
                _cT = string.gsub(_cT, "i%.o%:%[%'([%w+%s+%p+]+)%'%]", i_prt)

            -- i.i:$var  -- User input >$var
            elseif string.match(_cT, "i%.i%:$([%w%_]+)") then

                io.write ( " > " )
                local input = io.stdin:read"*l"

                if input ~= "" then
                    _cT = string.gsub(_cT, "i%.i%:$([%w%_]+)", function(w) _v[w] = tostring(input) end)
                else
                    _cT = string.gsub(_cT, "i%.i%:$([%w%_]+)", function(w) _v[w] = '' end)
                end

            -- i.r:['file']     -- Run File
            elseif string.match(_cT, "i%.r%:%[%'[%w+%s+%p+]+%'%]") then

                _cT = v_m(_cT)
                local input = ""
                _cT = string.gsub(_cT, "i%.r%:%[%'([%w+%s+%p+]+)%'%]", function (w) input = w end)

                if io.open (input, "r") then
                    local file = io.open(input, "r")
                    local str = file:read("*a")

                    for match in string.gfind(str, "%s*([^\n]*%S)") do

                        if string.match(match, "%#[%s+%w+%p+]+") then
                            match = string.gsub(match, "%#[%s+%w+%p+]+", "")
                        end
                        if match == "" then match = nil
                        else
                            table.insert(_t,match)
                        end
                    end
                end
                jump_rec(_t);
                process(_t)
                _t = {}
            end

        end
    end

---------------------------------------------------------------------------------------------
--  Jump Recorder:
--  Inserts into a table what code is used for a 'jump'

    function jump_rec(t)

        for i = 1, table.getn(t) do
            _cT = t[i]

            if string.match(_cT, "%%([%w%_]+)%:[%s]*%{") then

                local title = ""
                _cT = string.gsub(_cT, "%%([%w%_]+)%:[%s]*%{", function(w) title = w end)

                if string.match(_cT, "%%([%w%_]+)%:[%s]*%{") then
                    t[i] = ""
                    local a = i + 1
                    local code = {}

                    while true do
                        _cA = t[a]
                        if string.match(_cA, "^%}") then
                            t[a] = ""
                            break
                        else
                            table.insert(code, _cA)
                           t[a] = ""
                        end
                        a = a + 1
                    end
                    _j[title] = code
                end
            end
        end
    end

---------------------------------------------------------------------------------------------
--  Splits the source into table arrrays

    function tokeniser(line)

        for match in string.gfind(line, "%s*([^\n]*%S)") do

            if string.match(match, "%#[%s+%w+%p+]+") then
                match = string.gsub(match, "%#[%s+%w+%p+]+", "")
            end
            if match == "" then match = nil
            else
                table.insert(_c,match)
            end
        end
        jump_rec(_c);
    end

---------------------------------------------------------------------------------------------
--  Main Routine

    function main()                       -- Main program loop

        io.write ( ">> " );
        local input = io.stdin:read"*l"

        if input == "quit" then os.exit() end
        if input ~= "" or nil then

            tokeniser(input);           -- Ensure input is not blank
            process(_c);
            _c = {};
            _l = {};
            _t = {};
        end
        main();
    end

    io.write(":: Auo \n");
    main()