Last active
November 19, 2025 13:56
-
-
Save tnhung2011/f3ab20154b21c36fe878a47c13d68dab to your computer and use it in GitHub Desktop.
A batchfile Brainfuck interpreter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!-- : | |
| @echo off | |
| setlocal enableextensions enabledelayedexpansion | |
| set sy32=%systemroot:\Windows%=%\System32 | |
| set "tempFile=%temp%\strlen-bf.tmp" | |
| if "%~1" equ "" ( | |
| %sy32%\timeout /t 0 >nul 2>nul || ( | |
| 1>&2 ( | |
| echo ERROR: Can't use input redirection. (this breaks the input stream^) | |
| echo Please instead use the first argument to pass a script. | |
| ) | |
| exit /b 1 | |
| ) | |
| set /p code=|| exit /b 0 | |
| echo "!code!">"%tempFile%" | |
| set tempOffset=5 %= CR/LF, quotation marks and subtract by 1 =% | |
| ) else ( | |
| if not exist "%~1" ( | |
| 1>&2 echo ERROR: File %1 not found. | |
| exit /b 1 | |
| ) | |
| rem prevent awful for/f output buffering for commands | |
| rem https://stackoverflow.com/a/23374733 | |
| %sy32%\cscript //nologo //job:Init "%~f0?.wsf" %1 "%tempFile%" | |
| <"%tempFile%" set /p code=|| exit /b 0 | |
| set tempOffset=1 %= subtract by 1 =% | |
| ) | |
| :: strlen4 by dbenham | |
| :: http://ss64.org/viewtopic.php?id=424 | |
| for %%F in ("%tempFile%") do set /a len=%%~zF-%tempOffset% | |
| del "%tempFile%" | |
| call :fillJumpTable "!code!" | |
| call :parse "!code!" | |
| exit /b 0 | |
| :: inspired by https://github.com/mareek/BrainLuck/blob/master/Brainfuck.lua | |
| :fillJumpTable <string> | |
| set "str=%~1" | |
| set lpos= | |
| set /a "l_idx=0" | |
| for /l %%i in (0,1,!len!) do ( | |
| set c=!str:~%%i,1! | |
| if !c! equ [ ( | |
| set /a l_idx+=1 | |
| set lpos.!l_idx!=%%i | |
| ) else (if !c! equ ] ( | |
| 2>nul (for %%v in (lpos.!l_idx!) do set /a "jumpTable.!%%v!=%%i+1, jumpTable.%%i=!%%v!") | |
| set /a l_idx-=1 | |
| )) | |
| ) | |
| if %l_idx% neq 0 ( | |
| 1>&2 echo ERROR: Unbalanced brackets. | |
| (goto) 2>nul || exit /b | |
| ) | |
| ::set jumpTable | |
| exit /b | |
| :parse <String> | |
| set "str=%~1" | |
| set "inp=" | |
| set /a "p=0,idx=0" | |
| (set continue=set /a idx+=1 ^& goto parseLoop) | |
| set "unprintableChar=set/p=?<nul" | |
| call :prepareChar | |
| :parseLoop | |
| set c=!str:~%idx%,1! | |
| if [!c!] equ [] exit /b | |
| :: 8-bit arithmetics | |
| :: https://esolangs.org/wiki/Brainfuck_Powershell_interpreter | |
| if !c! equ + ( | |
| set /a "tape.%p%=(tape.%p%+1)%%256" | |
| %continue% | |
| ) | |
| if !c! equ - ( | |
| set /a "tape.%p%=(tape.%p%+255)%%256" | |
| %continue% | |
| ) | |
| if ^!c! equ ^> ( | |
| set /a p+=1 | |
| %continue% | |
| ) | |
| if ^!c! equ ^< ( | |
| set /a p-=1 | |
| %continue% | |
| ) | |
| if !c! equ . ( | |
| set t=!tape.%p%! | |
| if [!t!] equ [] (%continue%) | |
| if !t! equ 10 (echo.&%continue%) | |
| if defined char.!t! ( | |
| for %%a in (!t!) do <nul set/p=!char.%%a! | |
| ) else ( | |
| if !t! lss 33 (%unprintableChar% | |
| %continue%) | |
| if !t! gtr 126 (%unprintableChar% | |
| %continue%) | |
| %sy32%\cmd /c exit !t! | |
| <nul set/p="!=ExitCodeAscii!" | |
| ) | |
| %continue% | |
| ) | |
| if ^!c! equ ^, ( | |
| rem simulates getchar | |
| if not defined inp goto input | |
| set t=!inp:~%inp_idx%,1! | |
| if [!t!] equ [] ( | |
| :input | |
| set /p inp=|| goto input | |
| set /a inp_idx=0 | |
| ) | |
| for %%a in (!inp_idx!) do %sy32%\cscript //nologo //job:CharCode "%~f0?.wsf" "!inp:~%%a,1!" | |
| set tape.%p%=!errorlevel! | |
| set /a inp_idx+=1 | |
| %continue% | |
| ) | |
| if !c! equ [ ( | |
| if defined tape.%p% if !tape.%p%! neq 0 (%continue%) | |
| set idx=!jumpTable.%idx%! | |
| goto parseLoop | |
| ) | |
| if !c! equ ] ( | |
| set idx=!jumpTable.%idx%! | |
| goto parseLoop | |
| ) | |
| %continue% | |
| :prepareChar | |
| :: <BS> trick to insert <SP> and equal sign into variables | |
| :: https://stackoverflow.com/a/9865960 | |
| for /f %%A in ('prompt $H ^&echo on ^&for %%B in ^(1^) do rem') do set char.8=%%A | |
| set "char.32=.%char.8% " | |
| set "char.61=.%char.8%=" | |
| exit /b | |
| --> | |
| <package> | |
| <job id="Init"><script language="JScript"> | |
| var fs = new ActiveXObject("Scripting.FileSystemObject"); | |
| var content = fs.OpenTextFile(WScript.Arguments(0),1).ReadAll(); | |
| fs.OpenTextFile(WScript.Arguments(1),2,true).Write(content.match(/[\+\-\<\>\[\],\.]*/g).join('')); | |
| </script></job> | |
| <job id="CharCode"><script language="JScript"> | |
| WScript.Quit(WScript.Arguments(0).charCodeAt(0)); | |
| </script></job> | |
| </package> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment