diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0eea16b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/progs/ diff --git a/bf.exe b/bf.exe new file mode 100644 index 0000000..efe0ae5 Binary files /dev/null and b/bf.exe differ diff --git a/bfasm.exe b/bfasm.exe new file mode 100644 index 0000000..df17c72 Binary files /dev/null and b/bfasm.exe differ diff --git a/bfc.exe b/bfc.exe new file mode 100644 index 0000000..d1757e7 Binary files /dev/null and b/bfc.exe differ diff --git a/src/bf.bas b/src/bf.bas new file mode 100644 index 0000000..e11d7f4 --- /dev/null +++ b/src/bf.bas @@ -0,0 +1,273 @@ +Options: + $console:only + $noprefix + option explicit + option explicitarray + + +Constants: + const BF_DEC = 11 + const BF_EXT = "bc" + const BF_IF = 12 + const BF_IN = 15 + const BF_INC = 10 + const BF_LOOP = 13 + const BF_NOP = 0 + const BF_OUT = 14 + const BF_POP = 9 + const BF_PUSH = 8 + const BF_RET = 7 + const BF_TERM = "00" + const EMPTY = "" + const EXT_SEP = "." + const FOR_READING = "i" + const RESULT_NOP = -1 + const RESULT_RET = -8 + + +Globals: + dim shared as integer bvmData(0 to 262143) '256k of data memory + dim shared as long bvmDataPtr + dim shared as long bvmStack(0 to 65535) '64k of stack memory + dim shared as long bvmStackPtr + dim shared as integer IOresult + + +Variables: + dim as string bfFile + dim as string bvmCode + dim as string byteCode + dim as string fileName + dim as integer hi + dim as integer inFile + dim as integer lo + dim as integer result + dim as integer value + + +Exceptions: + IOresult = 0 + on error goto OnException + + +Begin: + bvmCode = EMPTY + fileName = trim$(command$) + bfFile = fileName + EXT_SEP + BF_EXT + + print + print "Brainfuck Virtual Machine 0.1" + print "(c) 2023 by 'Der Robert'" + print + print + + print "Attempt to open: " + bfFile + inFile = freefile + open FOR_READING, inFile, bfFile + if IOresult then + print "Could not access: " + bfFile + print "Check file and try again." + close + system + endif + + do until eof(inFile) + + byteCode = input$(1, inFile) + value = asc(byteCode) + + lo = value and 15 + hi = (value \ 16) and 15 + + bvmCode = bvmCode + hex$(lo) + hex$(hi) + + loop + + close + + print "Executing ..." + print + bvmDataPtr = lbound(bvmData) + bvmStackPtr = lbound(bvmStack) + + do + result = bvm(bvmCode) + if result = RESULT_NOP then exit do + if result = RESULT_RET then exit do + loop + + if pos(0) > 1 then print + print + print "Programme terminated with code: "; ltrim$(str$(result)) + print "> code '-1' means 'normal termination'" + print "> code '-8' means 'normal return'" + print + system +End + + +OnException: + IOresult = err +resume next + + +function bvm%(theCode as string) + dim as string bvmCode + dim as string byteCode + dim as byte isRunning + dim as string loopByte + dim as string loopCode + dim as byte openLoops + dim as integer result + dim as integer value + + bvmCode = theCode + isRunning = 1 + result = 0 + + while isRunning + + if isEmpty(bvmCode) then + isRunning = 0 + elseif left$(bvmCode, len(BF_TERM)) = BF_TERM then + isRunning = 0 + result = RESULT_NOP + endif + + byteCode = left$(bvmCode, 1) + bvmCode = mid$(bvmCode, 2) + + if isRunning then + + result = val("&H" + ucase$(byteCode)) + + select case result + case BF_DEC + bvmDecData + case BF_IF + loopCode = empty + openLoops = 1 + do + loopByte = ucase$(left$(bvmCode, 1)) + bvmCode = mid$(bvmCode, 2) + + if loopByte = hex$(BF_IF) then openLoops = openLoops + 1 + if loopByte = hex$(BF_LOOP) then openLoops = openLoops - 1 + if openLoops < 1 then exit do + + loopCode = loopCode + loopByte + loop + do + value = bvmGetData + if value = 0 then exit do + result = bvm(loopCode) + loop + case BF_IN + do + value = cvi(left$(inkey$ + mki$(0), 2)) + loop while value = 0 + bvmSetData value + case BF_INC + bvmIncData + case BF_LOOP + isRunning = 0 + case BF_NOP + 'NOP + case BF_OUT + print chr$(bvmGetData%); + case BF_POP + bvmPopData + case BF_PUSH + bvmPushData + case BF_RET + result = RESULT_RET + isRunning = 0 + 'case else + ' if pos(0) > 1 then print + ' print "Illegal bytecode: " + hex$(result%) + ' isRunning = 0 + end select + + endif + + wend + + bvm = result% +end function + + +function bvmGetData%() + bvmGetData = bvmData(bvmDataPtr) and 255 +end function + + +sub bvmSetData(value%) + bvmData(bvmDataPtr) = value% and 255 +end sub + + +sub bvmPopData() + if bvmDataPtr = lbound(bvmData) then + bvmDataPtr = ubound(bvmData) + else + bvmDataPtr = bvmDataPtr - 1 + endif +end sub + + +function bvmPopStack%() + if bvmStackPtr = lbound(bvmStack) then + bvmStackPtr = ubound(bvmStack) + else + bvmStackPtr = bvmStackPtr - 1 + endif + bvmPopStack = bvmStack(bvmStackPtr) +end function + + +sub bvmDecData + bvmData(bvmDataPtr) = (bvmData(bvmDataPtr) - 1) and 255 +end sub + + +sub bvmIncData + bvmData(bvmDataPtr) = (bvmData(bvmDataPtr) + 1) and 255 +end sub + + +sub bvmPushData + if bvmDataPtr = ubound(bvmData) then + bvmDataPtr = lbound(bvmData) + else + bvmDataPtr = bvmDataPtr + 1 + endif +end sub + + +sub bvmPushStack(stack as integer) + bvmStack(bvmStackPtr) = stack and 255 + if bvmStackPtr = ubound(bvmStack) then + bvmStackPtr = lbound(bvmStack) + else + bvmStackPtr = bvmStackPtr + 1 + endif +end sub + + +function isEmpty%(st as string) + isEmpty = (st = EMPTY) +end function + + +function reverse$(st as string) + dim as integer i + dim as string result + + result = EMPTY + for i = 1 to len(st) + result = mid$(st, i, 1) + result + next + + reverse = result +end function + diff --git a/src/bfasm.bas b/src/bfasm.bas new file mode 100644 index 0000000..245b1fb --- /dev/null +++ b/src/bfasm.bas @@ -0,0 +1,180 @@ +Options: + $console:only + $noprefix + option explicit + + +Constants: + const CHAR_SPACE = 32 + const CHAR_NBSP = 255 + const DEST_EXT = "bc" + const EMPTY = "" + const FOR_READING = "i" + const FOR_WRITING = "o" + const NULL_BYTE = 0 + const SRC_EXT = "bfa" + + +Globals: + dim shared as integer IOresult + dim shared as string Token_Sep + + +Variables: + dim as string bfLine + dim as string bfToken + dim as string byteCode + dim as string ch + dim as integer currentLine + dim as string destFile + dim as string fileName + dim as integer i + dim as integer inFile + dim as integer outFile + dim as string srcFile + dim as integer tokenPos + dim as integer value + + +Exceptions: + IOresult = 0 + on error goto OnException + + +Begin: + byteCode = EMPTY + bfLine = EMPTY + Token_Sep = chr$(CHAR_SPACE) + currentLine = 0 + fileName = trim$(command$) + srcFile = fileName + "." + SRC_EXT + destFile = fileName + "." + DEST_EXT + + print + print "Brainfuck Assembler 0.1" + print "(c) 2023 by 'Der Robert'" + print + print + + print "Attempt to open: " + srcFile + inFile = freefile + open FOR_READING, inFile, srcFile + if IOresult then + print "Could not find: " + srcFile + print "Check file and try again." + close + system + endif + + print "Attempt to prepare: " + destFile + outFile = freefile + open FOR_WRITING, outFile, destFile + if IOresult > 0 then + print "Could not prepare output file: " + srcFile + print "Check file access and try again." + close + system + endif + + print + print "Writing file ..." + + do until eof(inFile) + + if bfLine = EMPTY then + line input #inFile, bfLine + currentLine = currentLine + 1 + bfLine = trim$(bfLine) + endif + + for i = 1 to len(bfLine) + ch = mid$(bfLine, i, 1) + if asc(ch) < CHAR_SPACE then mid$(bfLine, i, 1) = Token_Sep + if asc(ch) = CHAR_NBSP then mid$(bfLine, i, 1) = Token_Sep + next + + tokenPos = instr(1, bfLine, Token_Sep) + if tokenPos > 0 then + bfToken = rtrim$(left$(bfLine, tokenPos)) + bfLine = ltrim$(mid$(bfLine, tokenPos)) + else + bfToken = bfLine + bfLine = EMPTY + endif + + select case lcase$(bfToken) + case "st_0", "nop" + byteCode = "0" + byteCode + case "st_1" + byteCode = "1" + byteCode + case "st_2" + byteCode = "2" + byteCode + case "st_3" + byteCode = "3" + byteCode + case "st_4" + byteCode = "4" + byteCode + case "st_5" + byteCode = "5" + byteCode + case "st_6" + byteCode = "6" + byteCode + case "st_7", "ret" + byteCode = "7" + byteCode + case "st_8", "push" + byteCode = "8" + byteCode + case "st_9", "pop" + byteCode = "9" + byteCode + case "st_a", "add", "inc" + byteCode = "A" + byteCode + case "st_b", "dec", "sub" + byteCode = "B" + byteCode + case "st_c", "if", "while" + byteCode = "C" + byteCode + case "st_d", "loop", "loopne", "loopnz" + byteCode = "D" + byteCode + case "st_e", "cout", "out" + byteCode = "E" + byteCode + case "st_f", "cin", "in", "inp" + byteCode = "F" + byteCode + case else + if left$(bfToken, 1) = ";" then + bfLine = EMPTY + elseif bfToken <> EMPTY then + close + kill destFile + print "Error in line:"; currentLine + print "Unrecognized token: " + bfToken + system + endif + end select + + if len(byteCode) = 2 then + print byteCode + Token_Sep; + value = val("&H" + byteCode) + print #outFile, chr$(value); + byteCode = EMPTY + endif + + loop + + if len(byteCode) = 1 then + print "0" + byteCode + Token_Sep; + value = val("&H0" + byteCode) + print #outFile, chr$(value); + endif + + print "00" + print #outFile, chr$(NULL_BYTE); + + close + + print + print "Compiled successfully." + print + + system +End + +OnException: + IOresult = err +resume next + diff --git a/src/bfc.bas b/src/bfc.bas new file mode 100644 index 0000000..22a23a9 --- /dev/null +++ b/src/bfc.bas @@ -0,0 +1,175 @@ +Options: + $console:only + $noprefix + option explicit + + +Constants: + const CHAR_SPACE = 32 + const DEST_EXT = "bc" + const EMPTY = "" + const EXT_SEP = "." + const FOR_READING = "i" + const FOR_WRITING = "o" + const NULL_BYTE = 0 + const NUMBER_LIST = "0123456789" + const SRC_EXT = "bf" + const TEMP_EXT = "bc.tmp" + const TOKEN_LIST = "><+-[].," + + +Globals: + dim shared as integer IOresult + dim shared as string Token_Sep + + +Variables: + dim as string bfToken + dim as string byteCode + dim as integer count + dim as string destFile + dim as string fileName + dim as integer inFile + dim as string kind + dim as integer outFile + dim as string push + dim as string srcFile + dim as string tempFile + dim as integer value + + +Exceptions: + IOresult = 0 + on error goto OnException + + +Begin: + byteCode = EMPTY + push = EMPTY + Token_Sep = chr$(CHAR_SPACE) + + fileName = trim$(command$) + srcFile = fileName + EXT_SEP + SRC_EXT + destFile = fileName + EXT_SEP + DEST_EXT + tempFile = fileName + EXT_SEP + TEMP_EXT + + print + print "Brainfuck Compiler 0.1" + print "(c) 2023 by 'Der Robert'" + print + print + + print "Attempt to open: " + srcFile + inFile = freefile + open FOR_READING, inFile, srcFile + if IOresult then + print "Could not access: " + srcFile + print "Check file and try again." + close + system + endif + + print "Attempt to prepare: " + destFile + outFile = freefile + open FOR_WRITING, outFile, tempFile + if IOresult then + print "Could not access output file: " + destFile + print "Check file access and try again." + close + system + endif + + print + print "Writing file ..." + + do until eof(inFile) + + bfToken = input$(1, inFile) + + if instr(TOKEN_LIST, bfToken) then + + if len(push) = 1 then + print #outFile, push; + push = EMPTY + elseif len(push) > 1 then + print #outFile, mid$(push, 2); + push = EMPTY + endif + + push = bfToken + + elseif instr(NUMBER_LIST, bfToken) then + + count = val(bfToken) + if(len(push) = 1) and(count = 0) then + push$ = EMPTY + else + kind = left$(push, 1) + push = push + string$(count, kind) + endif + + endif + + loop + + if len(push) = 1 then + print #outFile, push; + push = EMPTY + elseif len(push) > 1 then + print #outFile, mid$(push, 2); + push = EMPTY + endif + + close + + open FOR_READING, inFile, tempFile + + open FOR_WRITING, outFile, destFile + + do until eof(inFile) + + bfToken = input$(1, inFile) + + select case bfToken + case ">": byteCode = "8" + byteCode + case "<": byteCode = "9" + byteCode + case "+": byteCode = "A" + byteCode + case "-": byteCode = "B" + byteCode + case "[": byteCode = "C" + byteCode + case "]": byteCode = "D" + byteCode + case ".": byteCode = "E" + byteCode + case ",": byteCode = "F" + byteCode + end select + + if len(byteCode) = 2 then + print byteCode + Token_Sep; + value = val("&H" + byteCode) + print #outFile, chr$(value); + byteCode = EMPTY + endif + + loop + + if len(byteCode) = 1 then + print "0" + byteCode + Token_Sep; + value = val("&H0" + byteCode) + print #outFile, chr$(value); + endif + + print "00" + print #outFile, chr$(NULL_BYTE); + + close + kill tempFile + + print + print "Compiled successfully." + print + + system +End + +OnException: + IOresult = err +resume next +