Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --------INIT--------
- local tArgs = { ... }
- _w, _h = term.getSize()
- _BAS_VER = "6"
- if fs.exists( "hiresAPI" ) == false then
- shell.run( "pastebin", "get", "TFFJwxvp", "hiresAPI" )
- os.loadAPI( "hiresAPI" )
- print( "Using oli414's Canvas API" )
- sleep( 3 )
- else
- os.loadAPI( "hiresAPI" )
- end
- canvas = {}
- --***COMPLETE COPY OF CC READ FUNCTION***--
- local function _read( _sReplaceChar, _tHistory, _fnComplete, _sDefault )
- if _sReplaceChar ~= nil and type( _sReplaceChar ) ~= "string" then
- error( "bad argument #1 (expected string, got " .. type( _sReplaceChar ) .. ")", 2 )
- end
- if _tHistory ~= nil and type( _tHistory ) ~= "table" then
- error( "bad argument #2 (expected table, got " .. type( _tHistory ) .. ")", 2 )
- end
- if _fnComplete ~= nil and type( _fnComplete ) ~= "function" then
- error( "bad argument #3 (expected function, got " .. type( _fnComplete ) .. ")", 2 )
- end
- if _sDefault ~= nil and type( _sDefault ) ~= "string" then
- error( "bad argument #4 (expected string, got " .. type( _sDefault ) .. ")", 2 )
- end
- term.setCursorBlink( true )
- local sLine
- if type( _sDefault ) == "string" then
- sLine = _sDefault
- else
- sLine = ""
- end
- local nHistoryPos
- local nPos = #sLine
- if _sReplaceChar then
- _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
- end
- local tCompletions
- local nCompletion
- local function recomplete()
- if _fnComplete and nPos == string.len(sLine) then
- tCompletions = _fnComplete( sLine )
- if tCompletions and #tCompletions > 0 then
- nCompletion = 1
- else
- nCompletion = nil
- end
- else
- tCompletions = nil
- nCompletion = nil
- end
- end
- local function uncomplete()
- tCompletions = nil
- nCompletion = nil
- end
- local w = term.getSize()
- local sx = term.getCursorPos()
- local function redraw( _bClear )
- local nScroll = 0
- if sx + nPos >= w then
- nScroll = (sx + nPos) - w
- end
- local cx,cy = term.getCursorPos()
- term.setCursorPos( sx, cy )
- local sReplace = (_bClear and " ") or _sReplaceChar
- if sReplace then
- term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) )
- else
- term.write( string.sub( sLine, nScroll + 1 ) )
- end
- if nCompletion then
- local sCompletion = tCompletions[ nCompletion ]
- local oldText, oldBg
- if not _bClear then
- oldText = term.getTextColor()
- oldBg = term.getBackgroundColor()
- term.setTextColor( colors.white )
- term.setBackgroundColor( colors.gray )
- end
- if sReplace then
- term.write( string.rep( sReplace, string.len( sCompletion ) ) )
- else
- term.write( sCompletion )
- end
- if not _bClear then
- term.setTextColor( oldText )
- term.setBackgroundColor( oldBg )
- end
- end
- term.setCursorPos( sx + nPos - nScroll, cy )
- end
- local function clear()
- redraw( true )
- end
- recomplete()
- redraw()
- local function acceptCompletion()
- if nCompletion then
- -- Clear
- clear()
- -- Find the common prefix of all the other suggestions which start with the same letter as the current one
- local sCompletion = tCompletions[ nCompletion ]
- sLine = sLine .. sCompletion
- nPos = string.len( sLine )
- -- Redraw
- recomplete()
- redraw()
- end
- end
- while true do
- local sEvent, param = os.pullEventRaw()
- if sEvent == "terminate" then
- return 0xE7D
- elseif sEvent == "char" then
- -- Typed key
- clear()
- sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
- nPos = nPos + 1
- recomplete()
- redraw()
- elseif sEvent == "paste" then
- -- Pasted text
- clear()
- sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
- nPos = nPos + string.len( param )
- recomplete()
- redraw()
- elseif sEvent == "key" then
- if param == keys.enter then
- -- Enter
- if nCompletion then
- clear()
- uncomplete()
- redraw()
- end
- break
- elseif param == keys.left then
- -- Left
- if nPos > 0 then
- clear()
- nPos = nPos - 1
- recomplete()
- redraw()
- end
- elseif param == keys.right then
- -- Right
- if nPos < string.len(sLine) then
- -- Move right
- clear()
- nPos = nPos + 1
- recomplete()
- redraw()
- else
- -- Accept autocomplete
- acceptCompletion()
- end
- elseif param == keys.up or param == keys.down then
- -- Up or down
- if nCompletion then
- -- Cycle completions
- clear()
- if param == keys.up then
- nCompletion = nCompletion - 1
- if nCompletion < 1 then
- nCompletion = #tCompletions
- end
- elseif param == keys.down then
- nCompletion = nCompletion + 1
- if nCompletion > #tCompletions then
- nCompletion = 1
- end
- end
- redraw()
- elseif _tHistory then
- -- Cycle history
- clear()
- if param == keys.up then
- -- Up
- if nHistoryPos == nil then
- if #_tHistory > 0 then
- nHistoryPos = #_tHistory
- end
- elseif nHistoryPos > 1 then
- nHistoryPos = nHistoryPos - 1
- end
- else
- -- Down
- if nHistoryPos == #_tHistory then
- nHistoryPos = nil
- elseif nHistoryPos ~= nil then
- nHistoryPos = nHistoryPos + 1
- end
- end
- if nHistoryPos then
- sLine = _tHistory[nHistoryPos]
- nPos = string.len( sLine )
- else
- sLine = ""
- nPos = 0
- end
- uncomplete()
- redraw()
- end
- elseif param == keys.backspace then
- -- Backspace
- if nPos > 0 then
- clear()
- sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
- nPos = nPos - 1
- recomplete()
- redraw()
- end
- elseif param == keys.home then
- -- Home
- if nPos > 0 then
- clear()
- nPos = 0
- recomplete()
- redraw()
- end
- elseif param == keys.delete then
- -- Delete
- if nPos < string.len(sLine) then
- clear()
- sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
- recomplete()
- redraw()
- end
- elseif param == keys["end"] then
- -- End
- if nPos < string.len(sLine ) then
- clear()
- nPos = string.len(sLine)
- recomplete()
- redraw()
- end
- elseif param == keys.tab then
- -- Tab (accept autocomplete)
- acceptCompletion()
- end
- elseif sEvent == "term_resize" then
- -- Terminal resized
- w = term.getSize()
- redraw()
- end
- end
- local cx, cy = term.getCursorPos()
- term.setCursorBlink( false )
- term.setCursorPos( w + 1, cy )
- print()
- return sLine
- end
- local COLO = {
- [ 0x0 ] = 0x0001;
- [ 0x1 ] = 0x0002;
- [ 0x2 ] = 0x0004;
- [ 0x3 ] = 0x0008;
- [ 0x4 ] = 0x0010;
- [ 0x5 ] = 0x0020;
- [ 0x6 ] = 0x0040;
- [ 0x7 ] = 0x0080;
- [ 0x8 ] = 0x0100;
- [ 0x9 ] = 0x0200;
- [ 0xA ] = 0x0400;
- [ 0xB ] = 0x0800;
- [ 0xC ] = 0x1000;
- [ 0xD ] = 0x2000;
- [ 0xE ] = 0x4000;
- [ 0xF ] = 0x8000;
- }
- --------Bytecode--------
- local BC_HALT = 0x00
- local BC_GOSUB = 0x01
- local BC_ADD = 0x02
- local BC_SUB = 0x03
- local BC_VSET = 0x04
- local BC_VGET = 0x05
- local BC_ARGS = 0x06
- local BC_MUL = 0x07
- local BC_DIV = 0x08
- local BC_PUSH = 0x09
- local BC_POP = 0x0A
- local BC_CALL = 0x0B
- local BC_JUMP = 0x0C
- local BC_RET = 0x0D
- local BC_VFREE = 0x0E
- local BC_VDEF = 0x0F
- local BC_MOD = 0x10
- local BC_POW = 0x11
- local BC_CMP = 0x12
- local BC_JPC = 0x13
- local BC_STORE = 0x14
- local BC_LOAD = 0x15
- local BC_DUP = 0x16
- local BC_CARR = 0x17
- local BC_AND = 0x18
- local BC_OR = 0x19
- local BC_EXPECT = 0x20
- local opToName = {
- [ BC_HALT ] = { "HALT", 0 };
- [ BC_GOSUB ] = { "GOSUB", 0 };
- [ BC_ADD ] = { "ADD", 0 };
- [ BC_SUB ] = { "SUB", 0 };
- [ BC_VSET ] = { "VARSET", 1 };
- [ BC_VGET ] = { "VARGET", 1 };
- [ BC_ARGS ] = { "ARGS", 1 };
- [ BC_MUL ] = { "MUL", 0 };
- [ BC_DIV ] = { "DIV", 0 };
- [ BC_PUSH ] = { "PUSH", 1 };
- [ BC_POP ] = { "POP", 0 };
- [ BC_CALL ] = { "CALL", 1 };
- [ BC_JUMP ] = { "JUMP", 1 };
- [ BC_RET ] = { "RETURN", 0 };
- [ BC_VFREE ] = { "VARFREE", 1 };
- [ BC_VDEF ] = { "VARDEF", 1 };
- [ BC_MOD ] = { "MOD", 0 };
- [ BC_POW ] = { "POW", 0 };
- [ BC_CMP ] = { "COMPARE", 1 };
- [ BC_JPC ] = { "CONDJMP", 2 };
- [ BC_STORE ] = { "STORE", 1 };
- [ BC_LOAD ] = { "LOAD", 1 };
- [ BC_DUP ] = { "DUP", 0 };
- [ BC_AND ] = { "AND", 0 };
- [ BC_OR ] = { "OR", 0 };
- [ BC_CARR ] = { "REATEARRAY", 0 };
- [ BC_EXPECT ] = { "EXPECT", 1 };
- }
- local buttons = {
- 0, --LEFT
- 0, --RIGHT
- 0, --UP
- 0, --DOWN
- 0, --Z
- 0 --X
- }
- local allEvInputs = {}
- --------Interpreter--------
- local _PROGRAM_OFFSET = 1
- local memory = {}
- local stack = {}
- local jstack = {}
- local PC = 1
- local SP = 0
- local jSP = 0
- local isRunning = true
- EVENTS = {}
- --------Stack management--------
- local function spush( v )
- SP = SP + 1
- stack[ SP ] = v
- end
- local function rpush( v )
- jSP = jSP + 1
- jstack[ jSP ] = v
- end
- local function spop()
- if SP < 0 then
- printError( "BASIC: stack underflow" )
- printError( "PC: "..PC )
- isRunning = false
- return 0
- end
- local v = stack[ SP ]
- stack[ SP ] = nil
- SP = SP - 1
- return v
- end
- local function rpop()
- if jSP < 0 then
- printError( "BASIC: stack underflow" )
- printError( "PC: "..PC )
- isRunning = false
- return 0
- end
- local v = jstack[ jSP ]
- jstack[ jSP ] = nil
- jSP = jSP - 1
- return v
- end
- --------INPUT--------
- local currLine = 1
- local lineOffset = 1
- local currFile = ""
- local function inputFile( str )
- str=str.."\n"
- local p = 1
- currLine = 1
- lineOffset = 1
- return {
- [ "next" ] = function()
- local v = str:sub( p, p )
- lineOffset = lineOffset + 1
- if v == "\n" then
- currLine = currLine + 1
- lineOffset = 1
- end
- p = p + 1
- return v
- end;
- [ "peek" ] = function()
- return str:sub( p, p )
- end;
- [ "eof" ] = function()
- return p > #str
- end;
- [ "error" ] = function( msg )
- msg = msg or ""
- error( currFile..": "..currLine..", "..lineOffset.." -> "..msg, 0 )
- end;
- }
- end
- --------TOKENIZER--------
- local function tokenize( input )
- local function isNum( c )
- return c:match( "[0-9]" ) ~= nil
- end
- local function isChr( c )
- return c:match( "[_a-zA-Z]" ) ~= nil
- end
- local function isOp( c )
- return c:match( "[<=>%+%-/%*^%%]" ) ~= nil
- end
- local function isPunc( c )
- return c:match( "[.,%(%);:]" ) ~= nil
- end
- local function isWht( c )
- return c:match( "[ \t]" ) ~= nil
- end
- local function rw( p )
- local str = ""
- while input.eof() == false and p( input.peek() ) do
- str = str .. input.next()
- end
- return str
- end
- local function rws( p )
- local str = ""
- while input.eof() == false and p( input.peek() ) do
- if input.peek() == "\\" then
- input.next()
- str = str .. input.next()
- else
- str = str .. input.next()
- end
- end
- return str
- end
- local function rchr()
- return {
- [ "type" ] = "id";
- [ "value" ] = rw( isChr );
- }
- end
- local function rnum()
- local f = rw( isNum )
- if input.peek() == "." then
- input.next()
- if #f == 0 then
- f = "0"
- end
- f = f .."."..rw( isNum )
- end
- return {
- [ "type" ] = "num";
- [ "value" ] = f;
- }
- end
- local function rops()
- return {
- [ "type" ] = "op";
- [ "value" ] = rw( isOp );
- }
- end
- local function rpunc()
- return {
- [ "type" ] = "punc";
- [ "value" ] = input.next();
- }
- end
- local function rstring( p )
- input.next()
- local str = rws( function( p )
- return p ~= "\""
- end )
- if input.next() ~= p then
- input.error( "string not closed" )
- end
- return {
- [ "type" ] = "str";
- [ "value" ] = str;
- }
- end
- local function rnext()
- rw( isWht )
- if input.eof() == false then
- local p = input.peek()
- if p == "\n" then
- rw( function( c )
- return c == "\n"
- end )
- return {
- [ "type" ] = "newline";
- }
- elseif p == "\"" then
- return rstring( p )
- elseif isNum( p ) then
- return rnum()
- elseif p == "." then
- return rnum()
- elseif isChr( p ) then
- return rchr()
- elseif isOp( p ) then
- return rops()
- elseif isPunc( p ) then
- return rpunc()
- else
- input.next()
- return {
- [ "type" ] = "undef";
- }
- end
- else
- return {
- [ "type" ] = "EOF";
- }
- end
- end
- local curr
- return {
- [ "next" ] = function()
- local c = curr
- curr = nil
- return c or rnext()
- end;
- [ "peek" ] = function()
- if curr then return curr else
- curr = rnext()
- return curr
- end
- end;
- [ "eof" ] = input.eof;
- [ "error" ] = input.error;
- }
- end
- local PRECEDENCE = {
- [ "or" ] = 1,
- [ "and" ] = 2,
- [ "<" ] = 3, [ ">" ] = 3, [ "<=" ] = 3, [ ">=" ] = 3, [ "=" ] = 3, [ "<>" ] = 3,
- [ "+" ] = 4, [ "-" ] = 4,
- [ "*" ] = 5, [ "/" ] = 5, [ "%" ] = 5, [ "^" ] = 5
- };
- --------PARSER--------
- --------PARSER--------
- local function parse( input )
- local function expect( t, v, l )
- local i = input.next()
- if i.type == t then
- if v then
- if l == true then
- i.value = i.value:lower()
- end
- if v == i.value then
- return true
- else
- input.error( "expected value <"..v.."> got <"..i.value..">" )
- end
- else
- return i.value
- end
- else
- input.error( "expected type <"..t.."> got <"..i.type..">" )
- end
- end
- --Binary parsing
- local function atom()
- if input.peek().type == "num" then
- return input.next()
- elseif input.peek().type == "str" then
- return input.next()
- elseif input.peek().type == "id" then
- local v = input.next()
- if input.peek().value == "(" then
- return ecall( v.value )
- else
- return {
- [ "type" ] = "var_get";
- [ "name" ] = v.value;
- }
- end
- elseif input.peek().value == "(" then
- expect( "punc", "(" )
- local v = binary()
- expect( "punc", ")" )
- return v
- else
- input.error( "expected a value got "..input.peek().value )
- end
- end
- function binary( left, myPrc )
- local myPrc = myPrc or 0
- local left = left or atom()
- if input.peek().value == "and" or input.peek().value == "or" or input.peek().type == "op" then
- local prc = PRECEDENCE[ input.peek().value ]
- if prc > myPrc then
- local bin = {
- [ "type" ] = "binary";
- [ "op" ] = input.next().value;
- [ "left" ] = left;
- [ "right" ] = binary( atom(), prc );
- }
- return binary( bin, myPrc )
- end
- end
- return left
- end
- --Variable parsing
- local function vardef()
- expect( "id", "let", true )
- local name = expect( "id" )
- if input.peek().type == "op" then
- expect( "op", "=" )
- return {
- [ "type" ] = "var_defset";
- [ "name" ] = name;
- [ "value" ] = binary();
- }
- else
- return {
- [ "type" ] = "var_def";
- [ "name" ] = name;
- }
- end
- end
- local lineIndex = false
- local function varset( name )
- expect( "op", "=" )
- return {
- [ "type" ] = "var_set";
- [ "name" ] = name;
- [ "value" ] = binary();
- }
- end
- local function parseif()
- expect( "id", "if", true )
- local cond = binary()
- expect( "id", "then", true )
- return {
- [ "type" ] = "if";
- [ "cond" ] = cond;
- [ "then" ] = statement();
- }
- end
- local function parsedef()
- expect( "id", "def", true )
- local name = expect( "id" )
- expect( "punc", "(" )
- local vararg = {}
- while input.eof() == false do
- if input.peek().type == "id" then
- vararg[ #vararg + 1 ] = input.next().value
- elseif input.peek().value == "," then
- input.next()
- else
- break
- end
- end
- expect( "punc", ")" )
- expect( "op", "=" )
- local value
- if input.peek().value == "if" then
- value = parseif()
- else
- local l = atom()
- if input.peek().value == "=" then
- value = varset( l.name )
- else
- value = binary( l )
- end
- end
- return {
- [ "type" ] = "defun";
- [ "name" ] = name;
- [ "vararg" ] = vararg;
- [ "value" ] = value;
- }
- end
- local function parserem()
- expect( "id", "rem", true )
- while input.eof() == false do
- if input.peek().type == "newline" then
- break
- else
- input.next()
- end
- end
- expect( "newline" )
- end
- local function parsefor()
- expect( "id", "for", true )
- local vname = expect( "id" )
- expect( "op", "=" )
- local value = binary()
- expect( "id", "to", true )
- local to = binary()
- local step
- if input.peek().value == "step" then
- expect( "id", "step", true )
- step = binary()
- if input.peek().type == "newline" then
- input.next()
- end
- end
- local prog = {}
- local foundNext = false
- while input.eof() == false do
- local l = line()
- if type( l ) == "table" then
- prog[ #prog + 1 ] = l
- else
- foundNext = true
- break
- end
- end
- if foundNext == false then
- input.error( "for loop expected closing keyword 'next'" )
- end
- return {
- [ "type" ] = "loop";
- [ "var" ] = vname;
- [ "value" ] = value;
- [ "stepto" ] = to;
- [ "step" ] = step;
- [ "prog" ] = prog;
- }
- end
- --Function call parsing ( in LINE )
- local function lcargs()
- local args = {}
- if input.peek().type == "newline" then
- input.next()
- return args
- end
- while input.eof() == false do
- args[ #args + 1 ] = binary()
- if input.peek().value == "," then
- input.next()
- else
- if input.peek().value == "\n" then
- input.next()
- end
- break
- end
- end
- return args
- end
- local function lcall( name )
- return {
- [ "type" ] = "call";
- [ "name" ] = name:lower();
- [ "args" ] = lcargs();
- }
- end
- --Function call parsing ( in EXPRESSION )
- local function ecargs()
- expect( "punc", "(" )
- local args = {}
- while input.eof() == false do
- if input.peek().value == ")" then
- break
- end
- args[ #args + 1 ] = binary()
- if input.peek().value == "," then
- input.next()
- else
- if input.peek().value == "\n" then
- input.next()
- end
- break
- end
- end
- expect( "punc", ")" )
- return args
- end
- function ecall( name )
- return {
- [ "type" ] = "call";
- [ "name" ] = name:lower();
- [ "args" ] = ecargs();
- }
- end
- function statement( use_label )
- local p = input.peek()
- if p.value:lower() == "goto" then
- input.next()
- return {
- [ "type" ] = "goto";
- [ "value" ] = input.next().value;
- }
- elseif p.value:lower() == "gosub" then
- input.next()
- return {
- [ "type" ] = "gosub";
- [ "value" ] = binary();
- }
- elseif p.value:lower() == "return" then
- input.next()
- return { [ "type" ] = "return"; }
- elseif p.type == "id" then
- local v = input.next().value
- if input.peek().value == "=" then
- return varset( v )
- elseif input.peek().value == ":" then
- if use_label == true then
- input.next()
- return {
- [ "type" ] = "label";
- [ "name" ] = v;
- }
- else
- input.error( "can't define that label :( try it outside of 'if' :)" )
- end
- else
- return lcall( v )
- end
- else
- return binary()
- end
- end
- function line()
- if input.eof() == false and input.peek().type ~= "EOF" then
- if input.peek().type == "newline" then
- input.next()
- end
- local value, line
- if lineIndex == true then
- line = expect( "num" )
- end
- local p = input.peek()
- if p.value:lower() == "rem" then
- return parserem()
- elseif p.value:lower() == "def" then
- value = parsedef()
- elseif p.value:lower() == "let" then
- value = vardef()
- elseif p.value:lower() == "data" then
- input.next()
- value = {
- [ "type" ] = "array";
- [ "name" ] = expect( "id" );
- }
- elseif p.value:lower() == "if" then
- value = parseif()
- elseif p.value:lower() == "for" then
- value = parsefor()
- elseif p.value:lower() == "next" then
- input.next()
- if input.peek().type == "newline" then
- input.next()
- end
- return true
- else
- local v = {}
- while true do
- v[ #v + 1 ] = statement( true )
- if input.peek().value == ":" then
- input.next()
- else
- break
- end
- end
- value = v
- end
- if input.peek().type == "newline" then
- input.next()
- end
- return {
- [ "type" ] = "line";
- [ "line" ] = line or currLine;
- [ "value" ] = value;
- }
- end
- end
- local function program()
- local prog = {}
- if input.peek().type == "num" then
- lineIndex = true
- end
- while input.eof() == false do
- prog[ #prog + 1 ] = line()
- if input.peek().type == "newline" then
- input.next()
- end
- end
- return {
- [ "type" ] = "program";
- [ "prog" ] = prog;
- }
- end
- return program()
- end
- --------COMPILER--------
- local pc = 1
- local pcs = {}
- local currMem
- local function addToMem( ... )
- local v = { ... }
- for i=1, #v do
- currMem[ #currMem + 1 ] = v[ i ]
- pc = pc + 1
- end
- end
- local function addToMem2( ... )
- local v = { ... }
- for i=1, #v do
- currMem[ #currMem + 1 ] = v[ i ]
- end
- end
- local function preProcMem( ... )
- local v = { ... }
- for i=1, #v do
- pc = pc + 1
- end
- end
- local cifcount = 0
- local function preProcBin( op )
- if op == "=" or op == "<" or op == ">" or
- op == "<>" or op == ">=" or op == "<=" then
- preProcMem( 0, 1 )
- else
- preProcMem( 0 )
- end
- end
- local eop = 0
- local forloopc = 0
- local defuncs = {}
- local function preProcLabels( v )
- if v.type == "program" then
- for i=1, #v.prog do
- preProcLabels( v.prog[ i ] )
- end
- return
- elseif v.type == "line" then
- if #v.value > 0 then
- for i=1, #v.value do
- preProcLabels( v.value[ i ] )
- end
- else
- preProcLabels( v.value )
- end
- elseif v.type == "label" then
- preProcMem( BC_VDEF, 1 )
- preProcMem( BC_PUSH, 1 )
- preProcMem( BC_VSET, 1 )
- elseif v.type == "defun" then
- defuncs[ v.name ] = true
- preProcMem( BC_VDEF, 1 )
- preProcMem( BC_PUSH, 1 )
- preProcMem( BC_VSET, 1 )
- elseif v.type == "loop" then
- for i=1, #v.prog do
- preProcLabels( v.prog[ i ] )
- end
- end
- end
- local function preProc( v, env )
- if v.type == "program" then
- pc = _PROGRAM_OFFSET
- preProcLabels( v )
- for i=1, #v.prog do
- preProc( v.prog[ i ], env )
- end
- preProcMem( BC_HALT )
- eop = pc
- return
- elseif v.type == "line" then
- pcs[ v.line ] = pc
- if #v.value > 0 then
- for i=1, #v.value do
- preProc( v.value[ i ], env )
- end
- else
- preProc( v.value, env )
- end
- elseif v.type == "num" or v.type == "str" then
- preProcMem( BC_PUSH, v.value )
- elseif v.type == "label" then
- pcs[ v.name ] = pc
- addToMem2( BC_VDEF, v.name )
- addToMem2( BC_PUSH, pc )
- addToMem2( BC_VSET, v.name )
- elseif v.type == "defun" then
- preProcMem( BC_JUMP, 1 )
- addToMem2( BC_VDEF, v.name )
- addToMem2( BC_PUSH, pc )
- addToMem2( BC_VSET, v.name )
- preProcMem( BC_EXPECT, 1 )
- for i=1, #v.vararg do
- preProcMem( BC_VDEF, 1 )
- preProcMem( BC_VSET, 1 )
- end
- preProc( v.value )
- for i=1, #v.vararg do
- preProcMem( BC_VFREE, 1 )
- end
- preProcMem( BC_RET )
- defuncs[ v.name ] = pc
- elseif v.type == "goto" then
- preProcMem( BC_JUMP, 1 )
- elseif v.type == "return" then
- preProcMem( BC_RET )
- elseif v.type == "gosub" then
- if v.value.type == "num" then
- preProcMem( BC_PUSH, 1 )
- else
- preProc( v.value )
- end
- preProcMem( BC_GOSUB )
- elseif v.type == "array" then
- preProcMem( BC_VDEF, v.name )
- preProcMem( BC_CARR )
- preProcMem( BC_VSET, v.name )
- elseif v.type == "var_def" then
- preProcMem( BC_VDEF, v.name )
- elseif v.type == "var_defset" then
- preProcMem( BC_VDEF, v.name )
- preProc( v.value, env )
- preProcMem( BC_VSET, v.name )
- elseif v.type == "var_set" then
- preProc( v.value, env )
- preProcMem( BC_VSET, v.name )
- elseif v.type == "var_get" then
- preProcMem( BC_VGET, v.name )
- elseif v.type == "call" then
- for i=1, #v.args do
- preProc( v.args[ i ] )
- end
- if defuncs[ v.name ] then
- preProcMem( BC_ARGS, #v.args )
- preProcMem( BC_VGET, v.name )
- preProcMem( BC_GOSUB )
- else
- preProcMem( BC_ARGS, #v.args )
- preProcMem( BC_CALL, v.name )
- end
- elseif v.type == "if" then
- preProc( v.cond, env )
- preProcMem( BC_JPC, 0, 0 )
- preProc( v[ "then" ], env )
- pcs[ "if_end_"..cifcount ] = pc
- cifcount = cifcount + 1
- elseif v.type == "loop" then
- preProcMem( BC_VDEF, v.var )
- preProc( v.value, env )
- preProcMem( BC_VSET, v.var )
- if v.step then
- preProc( v.step, env )
- preProcMem( BC_STORE, 0 )
- end
- pcs[ "for_start_"..forloopc ] = pc
- forloopc = forloopc + 1
- for i=1, #v.prog do
- preProc( v.prog[ i ], env )
- end
- preProcMem( BC_VGET, v.var )
- if v.step then
- preProcMem( BC_LOAD, 0 )
- preProcMem( BC_ADD )
- preProcMem( BC_DUP )
- preProcMem( BC_VSET, v.var )
- else
- preProcMem( BC_PUSH, 1 )
- preProcMem( BC_ADD )
- preProcMem( BC_DUP )
- preProcMem( BC_VSET, v.var )
- end
- preProc( v.stepto, env )
- preProcMem( BC_CMP, 2 )
- preProcMem( BC_JPC, 0, 0 )
- preProcMem( BC_VFREE, v.var )
- elseif v.type == "binary" then
- preProc( v.left, env )
- preProc( v.right, env )
- preProcBin( v.op )
- end
- end
- local function printTable( t )
- local file = fs.open( "OUT", "w" )
- file.write( textutils.serialize( t ) )
- file.close()
- end
- local optBytes = 0
- local function optimizeBinary( l, r, op, v )
- if type( l ) == "number" and type( r ) == "number" then
- optBytes = optBytes + 4
- if op == "+" then
- v.type = "num"
- v.value = l + r
- elseif op == "-" then
- v.type = "num"
- v.value = l - r
- elseif op == "*" then
- v.type = "num"
- v.value = l * r
- elseif op == "/" then
- v.type = "num"
- v.value = l / r
- elseif op == "%" then
- v.type = "num"
- v.value = l % r
- elseif op == "^" then
- v.type = "num"
- v.value = l ^ r
- elseif op == "=" then
- v.type = "num"
- v.value = (l == r) and 1 or 0
- elseif op == "<>" then
- v.type = "num"
- v.value = l ~= r and 1 or 0
- elseif op == ">" then
- v.type = "num"
- v.value = l > r and 1 or 0
- elseif op == "<" then
- v.type = "num"
- v.value = l < r and 1 or 0
- elseif op == ">=" then
- v.type = "num"
- v.value = l >= r and 1 or 0
- elseif op == "<=" then
- v.type = "num"
- v.value = l <= r and 1 or 0
- elseif op == "and" then
- v.type = "num"
- v.value = ((l and r) == 1) and 1 or 0
- elseif op == "or" then
- v.type = "num"
- v.value = ((l or r) == 1) and 1 or 0
- else
- error( "BASIC: optimize error", 0 )
- end
- return true
- elseif type( l ) == "string" and type( r ) == "string" then
- optBytes = optBytes + #l + #r + 4
- if op == "+" then
- v.type = "str"
- v.value = l .. r
- else
- error( "BASIC: optimize error", 0 )
- end
- return true
- end
- return false
- end
- local backOne = false
- local function optimize( v, t )
- if v.type == "program" then
- local i = 1
- while i <= #v.prog do
- optimize( v.prog[ i ] )
- i = i + 1
- end
- --printTable( v )
- if t == nil then
- print( "OPTIMIZED: "..optBytes.." BYTES" )
- end
- elseif v.type == "num" then
- return tonumber( v.value )
- elseif v.type == "str" then
- return v.value
- elseif v.type == "line" then
- if #v.value > 0 then
- for j = 1, #v.value do
- while true do
- optimize( v.value[ j ] )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- end
- else
- optimize( v.value )
- end
- elseif v.type == "defun" then
- while true do
- backOne = false
- optimize( v.value )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- elseif v.type == "if" then
- while true do
- backOne = false
- optimize( v.cond )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- optimize( v[ "then" ] )
- elseif v.type == "var_defset" then
- while true do
- backOne = false
- optimize( v.value )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- elseif v.type == "var_set" then
- while true do
- backOne = false
- optimize( v.value )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- elseif v.type == "loop" then
- while true do
- backOne = false
- optimize( v.value )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- if v.step then
- while true do
- backOne = false
- optimize( v.step )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- end
- for i=1, #v.prog do
- optimize( v.prog[ i ] )
- end
- while true do
- backOne = false
- optimize( v.stepto )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- elseif v.type == "call" then
- for c=1, #v.args do
- while true do
- backOne = false
- optimize( v.args[ c ] )
- if backOne ~= true then
- backOne = false
- break
- end
- end
- end
- elseif v.type == "binary" then
- local c = optimizeBinary( optimize( v.left ), optimize( v.right ), v.op, v )
- if c == true then
- backOne = true
- end
- end
- end
- local function compileBinary( o )
- if o == "+" then
- addToMem( BC_ADD )
- elseif o == "-" then
- addToMem( BC_SUB )
- elseif o == "*" then
- addToMem( BC_MUL )
- elseif o == "/" then
- addToMem( BC_DIV )
- elseif o == "^" then
- addToMem( BC_POW )
- elseif o == "%" then
- addToMem( BC_MOD )
- elseif o == "=" then
- addToMem( BC_CMP, 0 )
- elseif o == "<" then
- addToMem( BC_CMP, 3 )
- elseif o == ">" then
- addToMem( BC_CMP, 2 )
- elseif o == ">=" then
- addToMem( BC_CMP, 4 )
- elseif o == "<=" then
- addToMem( BC_CMP, 5 )
- elseif o == "<>" then
- addToMem( BC_CMP, 1 )
- elseif o == "and" then
- addToMem( BC_AND )
- elseif o == "or" then
- addToMem( BC_OR )
- end
- end
- local ifcount = 0
- local varoffset = 1
- local forloop = 0
- local function comp( v, tt )
- if v.type == "program" then
- local prg = {}
- currMem = prg
- optBytes = 0
- optimize( v, tt )
- preProc( v, Enviroment() )
- pc = _PROGRAM_OFFSET
- for i=1, #v.prog do
- comp( v.prog[ i ] )
- end
- addToMem( BC_HALT )
- currMem = nil
- return prg
- elseif v.type == "line" then
- if #v.value > 0 then
- for i=1, #v.value do
- comp( v.value[ i ] )
- end
- else
- comp( v.value )
- end
- elseif v.type == "num" then
- addToMem( BC_PUSH, tonumber( v.value ) )
- elseif v.type == "str" then
- addToMem( BC_PUSH, v.value )
- elseif v.type == "goto" then
- addToMem( BC_JUMP, pcs[ v.value ] )
- elseif v.type == "gosub" then
- comp( v.value )
- addToMem( BC_GOSUB )
- elseif v.type == "return" then
- addToMem( BC_RET )
- elseif v.type == "array" then
- addToMem( BC_VDEF, v.name )
- addToMem( BC_CARR )
- addToMem( BC_VSET, v.name )
- elseif v.type == "defun" then
- addToMem( BC_JUMP, defuncs[ v.name ] )
- addToMem( BC_EXPECT, #v.vararg )
- for i=1, #v.vararg do
- addToMem( BC_VDEF, v.vararg[ i ] )
- addToMem( BC_VSET, v.vararg[ i ] )
- end
- comp( v.value )
- for i=1, #v.vararg do
- addToMem( BC_VFREE, v.vararg[ i ] )
- end
- addToMem( BC_RET )
- elseif v.type == "var_def" then
- addToMem( BC_VDEF, v.name )
- elseif v.type == "var_defset" then
- addToMem( BC_VDEF, v.name )
- comp( v.value )
- addToMem( BC_VSET, v.name )
- elseif v.type == "var_set" then
- comp( v.value )
- addToMem( BC_VSET, v.name )
- elseif v.type == "var_get" then
- addToMem( BC_VGET, v.name )
- elseif v.type == "call" then
- for i=1, #v.args do
- comp( v.args[ i ] )
- end
- if defuncs[ v.name ] then
- addToMem( BC_ARGS, #v.args )
- addToMem( BC_VGET, v.name )
- addToMem( BC_GOSUB )
- else
- addToMem( BC_ARGS, #v.args )
- addToMem( BC_CALL, v.name )
- end
- elseif v.type == "if" then
- comp( v.cond )
- addToMem( BC_JPC, 0, pcs[ "if_end_"..ifcount ] )
- ifcount = ifcount + 1
- comp( v[ "then" ] )
- elseif v.type == "loop" then
- addToMem( BC_VDEF, v.var )
- comp( v.value )
- addToMem( BC_VSET, v.var )
- local vof = varoffset
- varoffset = varoffset + 1
- local vfl = forloop
- forloop = forloop + 1
- if v.step then
- comp( v.step )
- addToMem( BC_STORE, eop+vof )
- end
- for i=1, #v.prog do
- comp( v.prog[i] )
- end
- addToMem( BC_VGET, v.var )
- if v.step then
- addToMem( BC_LOAD, eop+vof )
- addToMem( BC_ADD )
- addToMem( BC_DUP )
- addToMem( BC_VSET, v.var )
- else
- addToMem( BC_PUSH, 1 )
- addToMem( BC_ADD )
- addToMem( BC_DUP )
- addToMem( BC_VSET, v.var )
- end
- comp( v.stepto )
- addToMem( BC_CMP, 2 )
- addToMem( BC_JPC, 0, pcs[ "for_start_"..vfl ] )
- addToMem( BC_VFREE, v.var )
- elseif v.type == "binary" then
- comp( v.left )
- comp( v.right )
- compileBinary( v.op )
- end
- end
- local function compile( v, t )
- return comp( parse( tokenize( inputFile( v ) ) ), t )
- end
- local floor = math.floor
- --------INTERPRETER--------
- local queue = os.queueEvent
- local twrite = term.write
- local setBgCol = term.setBackgroundColor
- local setTxtCol = term.setTextColor
- local tSetPos = term.setCursorPos
- local highres = false
- local updated = false
- local function pxl( x, y, chr )
- if x <= _w and y <= _h and x > 0 and y > 0 then
- if highres == true then
- canvas:setPixel( floor( x ), floor( y ), true )
- updated = true
- else
- tSetPos( x, y )
- twrite( chr )
- end
- end
- end
- local function setColor( b, f )
- setBgCol( COLO[ b ] )
- setTxtCol( COLO[ f ] )
- end
- local function loadToMemory( m, off, r )
- local off = off or 0
- if r then
- memory = {}
- end
- for i=1, #m do
- memory[ off+i ] = m[ i ]
- end
- return #m
- end
- local _LOADED_FILES = {}
- local _CURR_FILES_OPENED = {}
- local _CURR_FILE_OPENED = 0
- local _CURR_NET_RECEIVE = {}
- local _CURR_NET_SEND = {}
- local _CURR_NET_USERS = {}
- local _CAN_NET_SEND = true
- local function simpleParse( str )
- str = str .. " "
- local t = {}
- local word = ""
- for i=1, #str do
- local chr = str:sub( i, i )
- if chr == " " or chr == "\t" or chr == "\n" then
- if #word > 0 then
- t[ #t + 1 ] = word
- word = ""
- end
- else
- word = word .. chr
- end
- end
- return t
- end
- local function generateIP( side )
- rednet.open( side )
- local count = 0
- local ip = math.random( 0xFF )..":"..math.random( 0xFF )..":"..math.random( 0xFF )
- while true do
- count = count + 1
- if count > 5 then
- break
- end
- rednet.broadcast( "check_ip "..ip, "basip" )
- local _, msg = rednet.receive( "basip", .5 )
- if msg == "" then
- break
- end
- msg = simpleParse( msg or "" )
- if msg[ 1 ] == "change_ip" then
- ip = math.random( 0xFF )..":"..math.random( 0xFF )..":"..math.random( 0xFF )
- else
- break
- end
- end
- rednet.close( side )
- return ip
- end
- local _timers = {}
- function Enviroment()
- return {
- [ "vars" ] = {
- [ "keystr" ] = "";
- [ "cycles" ] = 0;
- [ "createtimer" ] = function( time )
- _timers[ #_timers + 1 ] = time or 0
- return #_timers
- end;
- [ "settimer" ] = function( id, time )
- if _timers[ id ] then
- _timers[ id ] = time or 0
- end
- end;
- [ "gettimer" ] = function( id )
- if _timers[ id ] ~= nil then
- return _timers[ id ]
- end
- end;
- [ "print" ] = print;
- [ "write" ] = write;
- [ "input" ] = function( a, b )
- write( a.." " )
- return _read( b )
- end;
- [ "clear" ] = term.clear;
- [ "color" ] = setColor;
- [ "cursor" ] = tSetPos;
- [ "chr" ] = string.char;
- [ "int" ] = function( x )
- return floor( tonumber( x ) )
- end;
- [ "str" ] = tostring;
- [ "num" ] = tonumber;
- [ "len" ] = function( x )
- return #x
- end;
- [ "mid" ] = function( str, a, b )
- b = b or #str - a
- return str:sub( a, a+b )
- end;
- [ "left" ] = function( str, a )
- return str:sub( 1, a )
- end;
- [ "right" ] = function( str, a )
- a = a - 1
- return str:sub( #str-a, #str )
- end;
- [ "btn" ] = function( x )
- if buttons[ x ] then
- return buttons[ x ]
- end
- return 0
- end;
- [ "hex" ] = function( x )
- return tonumber( x, 16 )
- end;
- [ "abs" ] = math.abs;
- [ "atn" ] = math.atan;
- [ "cos" ] = math.cos;
- [ "sin" ] = math.sin;
- [ "exp" ] = math.exp;
- [ "log" ] = math.log;
- [ "rnd" ] = math.random;
- [ "sqr" ] = math.sqrt;
- [ "tan" ] = math.tan;
- [ "rad" ] = math.rad;
- [ "deg" ] = math.deg;
- [ "sgn" ] = function( x )
- if x < 0 then
- return -1
- elseif x > 0 then
- return 1
- else
- return 0
- end
- end;
- [ "fload" ] = function( fn, isbyte )
- if fs.exists( fn ) == false then
- return PC
- end
- if _LOADED_FILES[ fn ] then
- if _LOADED_FILES[ fn ][ 2 ] == cont then
- return _LOADED_FILES[ fn ][ 1 ]
- end
- end
- local mem
- if fn:sub( #fn-2, #fn ) == "bas" then
- local file = fs.open( fn, 'r' )
- local cont = file.readAll()
- currFile = fn
- mem = compile( cont, true )
- file.close()
- elseif fn:sub( #fn, #fn ) == "o" then
- mem = makeBytecode( readBytecodeFile( fn ) )
- end
- local s = _PROGRAM_OFFSET
- _LOADED_FILES[ fn ] = {
- s, cont
- }
- _PROGRAM_OFFSET = _PROGRAM_OFFSET + loadToMemory( mem, _PROGRAM_OFFSET - 1 )
- return s
- end;
- [ "fexists" ] = function( fn )
- if fs.exists( fn ) then
- return 1
- end
- return 0
- end;
- [ "flist" ] = fs.list;
- [ "fdel"] = fs.delete;
- [ "frdonly" ] = function( x )
- if fs.isReadOnly( x ) then
- return 1
- else
- return 0
- end
- end;
- [ "fisdir" ] = function( x )
- if fs.isDir( x ) then
- return 1
- else
- return 0
- end
- end;
- [ "fconext" ] = function()
- local n = #_CURR_FILES_OPENED
- if n == 0 then return end
- _CURR_FILE_OPENED = _CURR_FILE_OPENED + 1
- if _CURR_FILE_OPENED > n then
- _CURR_FILE_OPENED = 1
- end
- end;
- [ "fcoprev" ] = function()
- local n = #_CURR_FILES_OPENED
- if n == 0 then return end
- _CURR_FILE_OPENED = _CURR_FILE_OPENED - 1
- if _CURR_FILE_OPENED <= 0 then
- _CURR_FILE_OPENED = n
- end
- end;
- [ "fopen" ] = function( fn, t )
- if fs.exists( fn ) == false then return 0 end
- _CURR_FILE_OPENED = _CURR_FILE_OPENED + 1
- _CURR_FILES_OPENED[ _CURR_FILE_OPENED ] = fs.open( fn, t )
- return 1
- end;
- [ "fread" ] = function()
- if fileHeader ~= nil then
- return _CURR_FILES_OPENED[ _CURR_FILE_OPENED ].readAll()
- else
- return 0
- end
- end;
- [ "freadln" ] = function()
- if _CURR_FILES_OPENED[ _CURR_FILE_OPENED ] ~= nil then
- local ln = _CURR_FILES_OPENED[ _CURR_FILE_OPENED ].readLine()
- if ln == nil then
- return 0
- else
- return ln
- end
- else
- return 0
- end
- end;
- [ "fwrite" ] = function( x )
- if _CURR_FILES_OPENED[ _CURR_FILE_OPENED ] ~= nil then
- _CURR_FILES_OPENED[ _CURR_FILE_OPENED ].write( x )
- else
- return 0
- end
- end;
- [ "fwriteln" ] = function( x )
- if _CURR_FILES_OPENED[ _CURR_FILE_OPENED ] ~= nil then
- _CURR_FILES_OPENED[ _CURR_FILE_OPENED ].writeLine( x )
- else
- return 0
- end
- end;
- [ "fclose" ] = function()
- if _CURR_FILES_OPENED[ _CURR_FILE_OPENED ] ~= nil then
- _CURR_FILES_OPENED[ _CURR_FILE_OPENED ].close()
- _CURR_FILES_OPENED[ _CURR_FILE_OPENED ] = nil
- _CURR_FILE_OPENED = _CURR_FILE_OPENED - 1
- else
- return 0
- end
- end;
- [ "hires" ] = function()
- if fs.exists( "hiresAPI" ) == false then
- shell.run( "pastebin", "get", "TFFJwxvp", "hiresAPI" )
- os.loadAPI( "hiresAPI" )
- end
- canvas = hiresAPI.Canvas.create()
- highres = true
- _w = _w * 2
- _h = _h * 3
- end;
- [ "lores" ] = function()
- highres = false
- _w, _h = term.getSize()
- end;
- [ "pixel" ] = pxl;
- [ "sprite" ] = function( arr, x, y, w, h )
- x = x - 1
- y = y - 1
- local wh = (w*h)-1
- for i = 0, wh do
- if highres == false then
- if arr[ i+1 ] then
- setBgCol( COLO[ arr[ i+1 ] ] )
- end
- pxl( x + (i%w), y + (i/w), " " )
- else
- if arr[ i+1 ] == 0 then
- pxl( x + (i%w), y + (i/w) )
- end
- end
- end
- end;
- [ "store" ] = function( arr, x, y )
- if type( arr ) == "table" then
- arr[ x ] = y
- else
- printError( "BASIC: expected array to store to" )
- isRunning = false
- end
- end;
- [ "storen" ] = function( arr, x )
- if type( arr ) == "table" then
- arr[ #arr+1 ] = x
- else
- printError( "BASIC: expected array to store to" )
- isRunning = false
- end
- end;
- [ "read" ] = function( arr, x )
- if type( arr ) == "table" then
- return arr[ x ] or "none"
- else
- printError( "BASIC: expected array to read from" )
- isRunning = false
- end
- end;
- [ "shutdown" ] = function()
- print( "Shutdown in 5 seconds..." )
- sleep( 5 )
- os.shutdown()
- end;
- [ "reboot" ] = function()
- print( "Rebooting in 5 seconds..." )
- sleep( 5 )
- os.reboot()
- end;
- [ "label" ] = function( x )
- os.setComputerLabel( x )
- end;
- [ "exit" ] = function()
- isRunning = false
- end;
- [ "dispose" ] = function()
- while SP > 0 do
- spop()
- end
- end;
- [ "netcreate" ] = function( auto )
- local net = {}
- if auto then
- if peripheral.isPresent( auto ) then
- if peripheral.getType( auto ) == "modem" then
- net[ "side" ] = auto
- net[ "ip" ] = generateIP( auto )
- net[ "opened" ] = false
- else
- return
- end
- else
- return
- end
- else
- local side = ""
- local prhl = peripheral.getNames()
- for i=1, #prhl do
- if peripheral.getType( prhl[ i ] ) == "modem" then
- side = prhl[ i ]
- end
- end
- net[ "side" ] = side
- net[ "ip" ] = generateIP( side )
- net[ "opened" ] = false
- end
- return net
- end;
- [ "netopen" ] = function( net )
- if type( net ) == "table" then
- rednet.open( net[ "side" ] )
- net[ "opened" ] = true
- _CURR_NET_SEND = {
- [ "ip" ] = net.ip;
- [ "type" ] = "";
- [ "msg" ] = "";
- }
- _CURR_NET_USERS = {}
- end
- end;
- [ "netclose" ] = function( net )
- if type( net ) == "table" then
- rednet.close( net[ "side" ] )
- net[ "opened" ] = false
- end
- end;
- [ "netmyip" ] = function( net )
- if type( net ) == "table" then
- return net.ip
- end
- end;
- [ "netreceive" ] = function( net )
- if net[ "opened" ] == true then
- if _CURR_NET_USERS.senderIP then
- if _CURR_NET_USERS[ _CURR_NET_USERS.senderIP ] == nil then
- _CURR_NET_USERS[ _CURR_NET_USERS.senderIP ] = _CURR_NET_USERS.senderID
- end
- end
- end
- end;
- [ "netgetid" ] = function( net )
- if net[ "opened" ] == true then
- if _CURR_NET_RECEIVE.senderID then
- return _CURR_NET_RECEIVE.senderID
- end
- end
- return 0
- end;
- [ "netgetip" ] = function( net )
- if net[ "opened" ] == true then
- if _CURR_NET_RECEIVE.senderIP then
- return _CURR_NET_RECEIVE.senderIP
- end
- end
- return 0
- end;
- [ "netgettype" ] = function( net )
- if net[ "opened" ] == true then
- if _CURR_NET_RECEIVE.senderMsgType then
- return _CURR_NET_RECEIVE.senderMsgType
- end
- end
- return 0
- end;
- [ "netgetmessage" ] = function( net )
- if net[ "opened" ] == true then
- if _CURR_NET_RECEIVE.senderMsg then
- return _CURR_NET_RECEIVE.senderMsg
- end
- end
- return 0
- end;
- [ "netclearbuffer" ] = function()
- local ip = _CURR_NET_SEND.ip
- _CURR_NET_SEND = {
- [ "ip" ] = ip;
- [ "type" ] = "";
- [ "msg" ] = "";
- }
- end;
- [ "nettype" ] = function( t )
- _CURR_NET_SEND[ "type" ] = t
- end;
- [ "netmessage" ] = function( t )
- _CURR_NET_SEND[ "msg" ] = t
- end;
- [ "netsend" ] = function( ip )
- if _CAN_NET_SEND == true then
- if _CURR_NET_USERS[ ip ] == nil then
- rednet.broadcast( "ip "..ip, "basip" )
- local id, msg = rednet.receive( "basip" )
- local msg = simpleParse( msg or "" )
- if msg[ 1 ] == ip then
- _CURR_NET_USERS[ ip ] = id
- end
- end
- rednet.send( _CURR_NET_USERS[ ip ], _CURR_NET_SEND[ "ip" ].." ".._CURR_NET_SEND[ "type" ].." ".._CURR_NET_SEND[ "msg" ], "bas" )
- _CAN_NET_SEND = false
- end
- end;
- };
- [ "set" ] = function( self, x, y )
- local v = self.vars
- if v[ x ] then
- v[ x ] = y
- else
- printError( "BASIC: variable <"..x.."> is not defined!" )
- isRunning = false
- end
- end;
- [ "get" ] = function( self, x )
- local v = self.vars
- if v[ x ] then
- return v[ x ]
- else
- if x then
- printError( "BASIC: variable <"..x.."> is not defined!" )
- end
- isRunning = false
- return nil
- end
- end;
- [ "def" ] = function( self, x )
- self.vars[ x ] = 0
- end;
- [ "isDefined" ] = function( self, x )
- return self.vars[ x ] ~= nil
- end;
- [ "free" ] = function( self, x )
- local v = self.vars
- if v[ x ] then
- v[ x ] = nil
- else
- printError( "BASIC: variable <"..x.."> is not defined!" )
- isRunning = false
- end
- end;
- }
- end
- local function fetch()
- local v = memory[ PC ]
- PC = PC + 1
- return v
- end
- local function cycle( opcode, env )
- if opcode == BC_HALT then
- isRunning = false
- elseif opcode == BC_PUSH then
- spush( fetch() )
- elseif opcode == BC_POP then
- spop()
- elseif opcode == BC_VDEF then
- env:def( fetch() )
- elseif opcode == BC_VSET then
- env:set( fetch(), spop() )
- elseif opcode == BC_VGET then
- spush( env:get( fetch() ) )
- elseif opcode == BC_VFREE then
- env:free( fetch() )
- elseif opcode == BC_ARGS then
- local argc = fetch()
- local args = {}
- if (SP - argc) < 0 then
- printError( "BASIC: stack underflow" )
- printError( "PC: "..PC )
- isRunning = false
- return
- end
- for i=1, argc do
- args[ argc-(i-1) ] = spop()
- end
- spush( args )
- elseif opcode == BC_CALL then
- local ret = env:get( fetch() )( unpack( spop() ) )
- if ret then
- spush( ret )
- end
- elseif opcode == BC_ADD then
- local y = spop()
- local x = spop()
- if type( x ) == "string" or type( y ) == "string" then
- spush( x .. y )
- else
- spush( x + y )
- end
- elseif opcode == BC_SUB then
- local y = spop()
- spush( spop() - y )
- elseif opcode == BC_MUL then
- local y = spop()
- spush( spop() * y )
- elseif opcode == BC_DIV then
- local y = spop()
- spush( spop() / y )
- elseif opcode == BC_MOD then
- local y = spop()
- spush( spop() % y )
- elseif opcode == BC_POW then
- local y = spop()
- spush( spop() ^ y )
- elseif opcode == BC_JUMP then
- PC = fetch()
- elseif opcode == BC_GOSUB then
- local to = spop()
- rpush( PC )
- PC = to
- elseif opcode == BC_RET then
- PC = rpop()
- elseif opcode == BC_CMP then
- local t = fetch()
- local y = spop()
- if t == 0 then
- spush( spop() == y and 1 or 0 )
- elseif t == 1 then
- spush( spop() ~= y and 1 or 0 )
- elseif t == 2 then
- spush( spop() > y and 1 or 0 )
- elseif t == 3 then
- spush( spop() < y and 1 or 0 )
- elseif t == 4 then
- spush( spop() >= y and 1 or 0 )
- elseif t == 5 then
- spush( spop() <= y and 1 or 0 )
- end
- elseif opcode == BC_JPC then
- local cond
- local t = fetch()
- if spop() == t then
- PC = fetch()
- else
- PC = PC + 1
- end
- elseif opcode == BC_STORE then
- memory[ fetch() ] = spop()
- elseif opcode == BC_LOAD then
- spush( memory[ fetch() ] )
- elseif opcode == BC_DUP then
- local pop = spop()
- spush( pop )
- spush( pop )
- elseif opcode == BC_AND then
- local y = spop()
- spush( ((spop() and y) == 1) and 1 or 0 )
- elseif opcode == BC_OR then
- local y = spop()
- spush( ((spop() or y) == 1) and 1 or 0 )
- elseif opcode == BC_CARR then
- spush( {} )
- elseif opcode == BC_EXPECT then
- local v = spop()
- local n = fetch()
- if type( v ) ~= "table" then
- printError( "BASIC: interpreter error" )
- printError( "PC: "..PC )
- printError( "Expected: args" )
- isRunning = false
- end
- if n == #v then
- for i=#v, 1, -1 do
- spush( v[ i ] )
- end
- else
- printError( "BASIC: interpreter error" )
- printError( "PC: "..PC )
- printError( "Expected: "..n.." args" )
- isRunning = false
- end
- else
- printError( "BASIC: interpreter error" )
- printError( "PC: "..PC )
- printError( "STACK {" )
- for i=1, #stack do
- if i == #stack then
- write( stack[ i ] )
- else
- write( stack[ i ]..", " )
- end
- end
- print()
- printError( "}" )
- isRunning = false
- end
- end
- local bc_END_STRING = 0x0
- local bc_START_STRING = 0x1
- local bc_NEXT_BC = 0x2
- local bc_NEXT_ARG = 0x3
- local function makeByteTable( bc )
- local b = {}
- local check = false
- local i = 1
- while i <= #bc do
- local _byte = bc[ i ]
- if check == false then
- local m = opToName[ _byte ]
- if m[ 1 ] == "HALT" then
- check = true
- end
- b[ #b + 1 ] = bc_NEXT_BC
- b[ #b + 1 ] = _byte
- local _ = 0
- for j=1, m[ 2 ] do
- local v = bc[ i+j ]
- if type( v ) == "string" then
- b[ #b + 1 ] = bc_START_STRING
- for c=1, #v do
- b[ #b + 1 ] = string.byte( v:sub( c, c ) )
- end
- b[ #b + 1 ] = bc_END_STRING
- elseif type( v ) == "number" then
- b[ #b + 1 ] = bc_NEXT_ARG
- b[ #b + 1 ] = v
- end
- _ = _ + 1
- end
- i = (i + 1) + _
- else
- b[ #b + 1 ] = bc[ i ]
- i = i + 1
- end
- end
- return b
- end
- local function makeRunnableNET( fn, bc )
- local f=fn.."_tmp"
- local bcc = ""
- for i=1, #bc do
- local str = string.format( "%x", bc[ i ] )
- if #str == 1 then
- str = "0" .. str
- end
- bcc = bcc..str.." "
- end
- local file = fs.open( fn, 'w' )
- file.writeLine("local file=fs.open('"..f.."','w')")
- file.writeLine("file.write('"..bcc.."')")
- file.writeLine("file.close()")
- file.writeLine("shell.run('pastebin','run','nsMdcH6L','r','"..f.."')")
- file.writeLine("fs.delete('"..f.."')")
- file.close()
- end
- local function writeBytecodeToFile( fn, bc )
- local file = fs.open( fn, 'w' )
- local count = 1
- for i=1, #bc do
- if count >= 16 then
- count = 2
- file.write( "\n" )
- local str = string.format( "%x", bc[ i ] )
- if #str == 1 then
- str = "0" .. str
- end
- file.write( str .. " " )
- else
- local str = string.format( "%x", bc[ i ] )
- if #str == 1 then
- str = "0" .. str
- end
- count = count + 1
- file.write( str .. " " )
- end
- end
- file.close()
- end
- function readBytecodeFile( fn )
- local file = fs.open( fn, 'r' )
- local content = file.readAll()
- local t = {}
- file.close()
- for seg in content:gmatch "%S+" do
- t[#t + 1] = tonumber( seg, 16 )
- end
- return t
- end
- function makeBytecode( bc )
- local b = {}
- local check = false
- local i = 1
- local function fetch()
- local v = bc[ i ]
- i = i + 1
- return v
- end
- local function fetchString()
- local str = ""
- while true do
- local v = fetch()
- if v == bc_END_STRING then
- break
- else
- str = str .. string.char( v )
- end
- end
- return str
- end
- while i <= #bc do
- local tp = fetch()
- if tp == bc_NEXT_BC then
- local byte = fetch()
- local op = opToName[ byte ]
- local iter = op[ 2 ]
- b[ #b + 1 ] = byte
- for j=1, iter do
- local nx = fetch()
- if nx == bc_NEXT_ARG then
- local x = fetch()
- b[ #b + 1 ] = x
- elseif nx == bc_START_STRING then
- local x = fetchString()
- b[ #b + 1 ] = x
- else
- error( "Expected Start of String or Start of Argument!", 0 )
- end
- end
- else
- print( bc[ i-1 ] )
- error( "Expected bytecode!", 0 )
- end
- end
- return b
- end
- function interpret( env )
- PC = 1
- SP = 0
- jSP = 0
- stack = {}
- jstack = {}
- isRunning = true
- parallel.waitForAny( function()
- local vars = env.vars
- while true do
- EVENT = { os.pullEventRaw() }
- if EVENT[ 1 ] == "terminate" then
- return
- elseif EVENT[ 1 ] == "char" then
- vars.keystr = vars.keystr .. EVENT[ 2 ]
- elseif EVENT[ 1 ] == "key" then
- if EVENT[ 2 ] == keys.z then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 5 ] = 1;
- }
- elseif EVENT[ 2 ] == keys.x then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 6 ] = 1;
- }
- elseif EVENT[ 2 ] == keys.left then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 1 ] = 1;
- }
- elseif EVENT[ 2 ] == keys.right then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 2 ] = 1;
- }
- elseif EVENT[ 2 ] == keys.up then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 3 ] = 1;
- }
- elseif EVENT[ 2 ] == keys.down then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 4 ] = 1;
- }
- end
- elseif EVENT[ 1 ] == "key_up" then
- if EVENT[ 2 ] == keys.z then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 5 ] = 0;
- }
- elseif EVENT[ 2 ] == keys.x then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 6 ] = 0;
- }
- elseif EVENT[ 2 ] == keys.left then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 1 ] = 0;
- }
- elseif EVENT[ 2 ] == keys.right then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 2 ] = 0;
- }
- elseif EVENT[ 2 ] == keys.up then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 3 ] = 0;
- }
- elseif EVENT[ 2 ] == keys.down then
- allEvInputs[ #allEvInputs + 1 ] = {
- [ 4 ] = 0;
- }
- end
- end
- end
- end, function()
- local prhl = peripheral.getNames()
- local doSlp = false
- while true do
- doSlp = false
- for i=1, #prhl do
- if peripheral.getType( prhl[ i ] ) == "modem" then
- if rednet.isOpen( prhl[ i ] ) then
- local id, msg = rednet.receive( "basip" )
- msg = simpleParse( msg )
- msg[ 1 ] = msg[ 1 ] or ""
- msg[ 2 ] = msg[ 2 ] or ""
- if msg[ 1 ] == "check_ip" then
- if msg[ 2 ] == _CURR_NET_SEND.ip then
- rednet.send( id, "change_ip", "basip" )
- end
- elseif msg[ 1 ] == "ip" then
- if _CURR_NET_SEND.ip == msg[ 2 ] then
- rednet.send( id, _CURR_NET_SEND.ip, "basip" )
- end
- end
- else
- doSlp = true
- end
- else
- doSlp = true
- end
- end
- if doSlp then sleep( .1 ) end
- end
- end, function()
- local prhl = peripheral.getNames()
- local doSlp = false
- local lastIP = ""
- while true do
- doSlp = false
- lastIP = ""
- for i=1, #prhl do
- if peripheral.getType( prhl[ i ] ) == "modem" then
- if rednet.isOpen( prhl[ i ] ) then
- local id, msg = rednet.receive( "bas" )
- msg = simpleParse( msg )
- if lastIP == msg[ 1 ] then
- break
- end
- _CURR_NET_RECEIVE = {
- [ "senderID" ] = id;
- [ "senderIP" ] = msg[ 1 ] or "";
- [ "senderMsgType" ] = msg[ 2 ] or "";
- [ "senderMsg" ] = table.concat( msg, " ", 3 );
- }
- lastIP = msg[ 1 ]
- doSlp = false
- break
- else
- doSlp = true
- end
- else
- doSlp = true
- end
- end
- if doSlp then sleep( .1 ) end
- end
- end, function()
- local tblRem = table.remove
- while isRunning == true do
- local vars = env.vars
- if #allEvInputs > 0 then
- local evs = allEvInputs[ 1 ]
- for i=1, 6 do
- buttons[ i ] = evs[ i ] or 0
- end
- tblRem( allEvInputs, 1 )
- end
- for _=0, 0xFF do
- if isRunning == true then
- vars.cycles = _
- cycle( fetch(), env )
- if highres == true and updated == true then
- canvas:draw()
- updated = false
- end
- else
- break
- end
- end
- for i=1, #_timers do
- if _timers[ i ] > 0 then
- _timers[ i ] = _timers[ i ] - 1
- end
- end
- _CURR_NET_RECEIVE = {}
- _CAN_NET_SEND = true
- queue( "GET_FECH_BAS" )
- os.pullEventRaw( "GET_FECH_BAS" )
- end
- end )
- end
- local function getFileExt( file )
- for i=#file, 1, -1 do
- if file:sub( i, i ) == "." then
- return file:sub( 1, i-1 ), file:sub( i+1, #file )
- end
- end
- return file, ""
- end
- parallel.waitForAny( function()
- if #tArgs == 3 then
- if tArgs[ 1 ] == "c" then
- if fs.exists( tArgs[ 2 ] ) then
- local file = fs.open( tArgs[ 2 ], 'r' )
- currFile = tArgs[ 2 ]
- local bc = compile( file.readAll() )
- file.close()
- writeBytecodeToFile( tArgs[ 3 ], makeByteTable( bc ) )
- else
- printError( "File "..tArgs[ 2 ].." does not exist!" )
- printError( "Usage: BASIC c <in> <out> -> compile BASIC file" )
- printError( "Usage: BASIC r <in> -> load BASIC bytecode file" )
- printError( "Usage: BASIC <filename> -> run BASIC file" )
- printError( "Usage: BASIC -> run BASIC shell" )
- error()
- end
- elseif tArgs[ 1 ] == "m" then
- if fs.exists( tArgs[ 2 ] ) then
- local file = fs.open( tArgs[ 2 ], 'r' )
- local bc = compile( file.readAll() )
- file.close()
- makeRunnableNET( tArgs[ 3 ], makeByteTable( bc ) )
- end
- else
- printError( "Usage: BASIC c <in> <out> -> compile BASIC file" )
- printError( "Usage: BASIC r <in> -> load BASIC bytecode file" )
- printError( "Usage: BASIC <filename> -> run BASIC file" )
- printError( "Usage: BASIC -> run BASIC shell" )
- error()
- end
- elseif #tArgs == 2 then
- if tArgs[ 1 ] == "r" then
- if fs.exists( tArgs[ 2 ] ) then
- currFile = tArgs[ 2 ]
- local mem = makeBytecode( readBytecodeFile( tArgs[ 2 ] ) )
- _PROGRAM_OFFSET = _PROGRAM_OFFSET + loadToMemory( mem, nil, true )
- interpret( Enviroment() )
- else
- printError( "File "..tArgs[ 2 ].." does not exist!" )
- printError( "Usage: BASIC c <in> <out> -> compile BASIC file" )
- printError( "Usage: BASIC r <in> -> load BASIC bytecode file" )
- printError( "Usage: BASIC <filename> -> run BASIC file" )
- printError( "Usage: BASIC -> run BASIC shell" )
- error()
- end
- else
- printError( "Usage: BASIC c <in> <out> -> compile BASIC file" )
- printError( "Usage: BASIC r <in> -> load BASIC bytecode file" )
- printError( "Usage: BASIC <filename> -> run BASIC file" )
- printError( "Usage: BASIC -> run BASIC shell" )
- error()
- end
- elseif #tArgs == 1 then
- if fs.exists( tArgs[ 1 ] ) then
- local file = fs.open( tArgs[ 1 ], 'r' )
- currFile = tArgs[ 1 ]
- local mem = compile( file.readAll() )
- file.close()
- _PROGRAM_OFFSET = _PROGRAM_OFFSET + loadToMemory( mem, nil, true )
- interpret( Enviroment() )
- else
- printError( "File "..tArgs[ 1 ].." does not exist!" )
- printError( "Usage: BASIC c <in> <out> -> compile BASIC file" )
- printError( "Usage: BASIC r <in> -> load BASIC bytecode file" )
- printError( "Usage: BASIC <filename> -> run BASIC file" )
- printError( "Usage: BASIC -> run BASIC shell" )
- error()
- end
- elseif #tArgs == 0 then
- local function sayReady()
- print()
- print( "READY" )
- end
- local str = "**** ComputerCraft BASIC Version ".._BAS_VER.." ****"
- setBgCol( colors.blue )
- setTxtCol( colors.lightBlue )
- term.clear()
- term.setCursorPos( math.floor( _w/2-#str/2 ), 1 )
- write( str );str = "Made by LeDark Lua"
- term.setCursorPos( math.floor( _w/2-#str/2 ), 2 )
- write( str )
- print()
- currFile = "NEWFILE"
- local inputedCode = {}
- local maxLine = 1
- local env = Enviroment()
- sayReady()
- while true do
- local r = _read()
- if r == 0xE7D then return end
- local commands = simpleParse( r )
- if commands[ 1 ] == "new" then
- currFile = "NEWFILE"
- maxLine = 1
- inputedCode = {}
- env = Enviroment()
- sayReady()
- elseif commands[ 1 ] == "run" then
- _PROGRAM_OFFSET = 0
- local code = ""
- for i=1, maxLine do
- if inputedCode[ i ] then
- code = code .. inputedCode[ i ] .. "\n"
- end
- end
- _PROGRAM_OFFSET = _PROGRAM_OFFSET + loadToMemory( compile( code ), nil, true )
- interpret( env )
- _w, _h = term.getSize()
- sayReady()
- elseif commands[ 1 ] == "list" then
- if commands[ 2 ] == "bc" then
- local code = ""
- for i=1, maxLine do
- if inputedCode[ i ] then
- code = code .. inputedCode[ i ] .. "\n"
- end
- end
- loadToMemory( compile( code ) )
- local xoff = 1
- local i = 1
- local check = false
- while i <= #memory do
- local m = opToName[ memory[ i ] ]
- if check == false and m then
- if m[ 1 ] == "HALT" then
- check = true
- end
- local c = m[ 1 ].."( "
- local _ = 0
- for j=1, m[ 2 ] do
- c = c .. memory[ i+j ].." "
- _ = _ + 1
- end
- write( c..") " )
- i = i + _ + 1
- else
- write( "MEM[ "..memory[ i ].." ] " )
- i = i + 1
- end
- end
- print()
- else
- local s = commands[ 2 ] or 1
- local e = commands[ 3 ] or maxLine
- for i=s, e do
- if inputedCode[ i ] then
- print( inputedCode[ i ] )
- end
- end
- end
- sayReady()
- elseif commands[ 1 ] == "save" then
- if commands[ 2 ] then
- print( "Saving as: "..commands[ 2 ].."..." )
- currFile = commands[ 2 ]
- local file = fs.open( commands[ 2 ], 'w' )
- for i=1, maxLine do
- if inputedCode[ i ] then
- file.write( inputedCode[ i ].."\n" )
- end
- end
- file.close()
- print( "Saved." )
- else
- printError( "No file specified!" )
- end
- sayReady()
- elseif commands[ 1 ] == "load" then
- local sec = commands[ 2 ] or ""
- if sec:sub( #sec, #sec ) == "$" then
- local dir = sec:sub( 1, #sec-1 )
- maxLine = 1
- inputedCode = {}
- local files = fs.list( dir )
- inputedCode[ 1 ] = "FILE NAME EXT"
- for i=1, #files do
- local file, ext = getFileExt( files[ i ] )
- if fs.isDir( dir.."/"..files[ i ] ) == true then
- ext = "DIR"
- table.insert( inputedCode, 2, file..string.rep( " ", 41-#files[ i ] )..ext )
- elseif fs.isReadOnly( dir.."/"..files[ i ] ) then
- inputedCode[ #inputedCode+1 ] = file..string.rep( " ", 41-#files[ i ] ).."***"
- else
- inputedCode[ #inputedCode+1 ] = file..string.rep( " ", 41-#files[ i ] )..string.rep( " ", #ext+1 )..ext
- end
- max.Line = maxLine + 1
- end
- elseif sec ~= "" then
- maxLine = 1
- inputedCode = {}
- print( "Loading: "..commands[ 2 ].."..." )
- if fs.exists( commands[ 2 ] ) then
- currFile = commands[ 2 ]
- env = Enviroment()
- local file = fs.open( commands[ 2 ], 'r' )
- local l = 1
- while true do
- local line = file.readLine()
- if line == nil then break end
- if line ~= "" then
- line = simpleParse( line )
- if tonumber( line[ 1 ] ) then
- l = tonumber( line[ 1 ] )
- else
- l = l + 1
- end
- if l > maxLine then
- maxLine = l
- end
- inputedCode[ l ] = table.concat( line, " " )
- end
- end
- file.close()
- print( "Loaded." )
- else
- printError( "File doesn't exist!" )
- end
- else
- printError( "No file specified!" )
- end
- sayReady()
- elseif commands[ 1 ] == "clear" then
- term.setCursorPos( 1, 1 )
- term.clear()
- elseif commands[ 1 ] == "exit" then
- return
- else
- if #commands > 1 then
- local l = tonumber( commands[ 1 ] )
- if type( l ) == "number" then
- if l > maxLine then
- maxLine = l
- end
- inputedCode[ l ] = table.concat( commands, " " )
- end
- end
- end
- end
- else
- printError( "To many arguments!" )
- printError( "Usage: BASIC c <in> <out> -> compile BASIC file" )
- printError( "Usage: BASIC r <in> -> load BASIC bytecode file" )
- printError( "Usage: BASIC <filename> -> run BASIC file" )
- printError( "Usage: BASIC -> run BASIC shell" )
- error()
- end
- end )
- term.setTextColor( colors.white )
- term.setBackgroundColor( colors.black )
- print( "Thanks for using CCBASIC" )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement