at the REF link there is the "source" or the base that produce the bf ( automatically produced). Direct link
einstein1969
Moderator: DosItHelp
einstein1969 wrote:I want identify this code in the hanoi.bf It's possible?Code: Select all
macro delay()
{
var a = 200;
while (a) {
var b = 200;
while (b) {
var c = 100;
while (c) c -= 1;
b -= 1;
}
a -= 1;
}
}
There is not necessity to DELAY...
einstein1969
Code: Select all
;[629] +.>>>>>>]<<]<<<<<<+++++++++++++.<<[-]+++++++++++++++++++++++++++++++++++++++
"code[13371]=. 1"
"code[13372]=> 6"
"code[13373]=] 13367"
"code[13374]=< 2"
"code[13375]=] 13335"
"code[13376]=< 6"
"code[13377]=+ 13"
"code[13378]=. 1"
"code[13379]=< 2" // var a
"code[13380]== 200" // = 200;
"code[13381]=[ 13393" // while (a) {
;[630] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;[631] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;[632] +++++++++[>[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"code[13382]=> 1" // var b
"code[13383]== 200" // = 200;
"code[13384]=[ 13390" // while (b) {
;[633] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;[634] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[>[-]+++++++++
"code[13385]=> 1" // var c
"code[13386]== 100" // = 100;
"code[13387]== 0" // while (c) c -= 1;
;[635] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;[636] +++++++++++++++[-]<-]<-]<<<<<]<<<<+>>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<
"code[13388]=< 1" // b
"code[13389]=- 1" // -= 1;
"code[13390]=] 13384" // }
"code[13391]=< 1" // a
"code[13392]=- 1" // -= 1;
"code[13393]=] 13381" // }
"code[13394]=< 5"
"code[13395]=] 5168"
Code: Select all
+.>>>>>>]<<]<<<<<<+++++++++++++.<<[-]+++++++++++++++++++++++++++++++++++++++
Code: Select all
+.>>>>>>]<<]<<<<<<+++++++++++++.<<
Code: Select all
+++++++++++++++[-]<-]<-]<<<<<]<<<<+>>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<
Code: Select all
<<<<<]<<<<+>>>>[-]>[-]<<<<<[->>>>>+<<<<<]>>>>>[-<+<<
Extract Subs:
-------------
Aacini 3.0 12:46:39,07 - 12:46:39,65 Elapsed 58 cs
Parse:
------
JWinslow23 about 100 cs
dbenham 2.0 17:52:39,35 - 17:52:39,59 elapsed 24 cs
Aacini 2.1 17:41:46,55 - 17:41:48,98 elapsed 243 cs
dbenham 2.0 optimized about 25 cs
JWinslow23 optimized about 180 cs
Aacini 3.0 12:46:39,65 - 12:46:40,16 Elapsed 51 cs
dbenham 3.0 Parsing code Elapsed time 21 cs
Prepare memory:
---------------
JWinslow23 about 300 cs
JWinslow23 optimized about 800 cs
Loading parsed file:
--------------------
Aacini 2.1 18:08:33,67 - 18:08:33,70 elapsed 3 cs
Saving parsed file:
-------------------
Aacini 2.1 17:41:48,99 - 17:41:49,05 elapsed 6 cs
Run:
----
JWinslow23 about 75-100 cycles/s
dbenham 2.0 about 800 cycles/s
Aacini 2.1 about 750 cycles/s
dbenham 2.0 opt. about 800 cycles/s
JWinslow23 opt. about 130-140 cycles/s
dbenham 2.0 opt.12:59:28,01 - 12:59:17,77 Elapsed 85.26 s
Aacini 3.0 12:44:38,88 - 12:45:51,94 Elapsed 73.06 s
dbenham 3.0 Execute : Elapsed time 30.61 s
Parse:
------
dbenham 3.0 Elapsed time 425.08 s
Aacini 3.0 Extracting sub. 15:48:12,54 - 15:49:34,61 Elapsed 82.07 s
Aacini 3.0 Parsing sub. 15:49:34,63 - 15:49:55,75 Elapsed 21.12 s
denham 2.0 Mod 15:56:20,22 - 15:57:00,75 Elapsed 40.53 s
denham 3.0 Mod Elapsed time = 37.33 s
Run:
----
dbenham 3.0 15:32:18,53 - 15:40:14,48 Elapsed 484.05 s
Aacini 3.0 15:49:56,00 - 15:51:05,40 - 15:52:11,86 Elapsed 69.04 s 135.86 s
denham 2.0 mod 15:57:11,33 - 15:57:54,29 - 15:58:33,32 Elapsed 42.96 s 81.99 s
denham 3.0 mod 17:57:20,63 - 17:57:50,81 - 17:58:17,16 Elapsed 30.18 s 56.53 s
Code: Select all
::BF.BAT - BrainF*** interpreter in Batch, dbenham version 4.0
::
:: Usage:
::
:: bf sourceFile [-option [value]]...
::
:: Options
::
:: -i Filename = read Input from file Filename.
::
:: -z = <Ctrl-Z> terminates keyboard input (forces EOF).
::
:: -e Value = EOF value: Sets value read into memory upon End-Of-File.
:: Default is no change to memory.
::
:: -ee = terminate with Error if attempt is made to read past EOF.
::
:: -eo = terminate with Error if +/- results in Overflow.
::
:: -em = terminate with Error if < yields a negative Memory address.
::
:: -ea = terminate with Error on Any fault. Same as -ee -eo -em
::
:: -s = Silent mode. Don't print initialization messages, elapsed
:: times, or run statistics. Also disables the -l option.
::
:: -d Filename = Dump the parsed op codes to Filename.
:: Use con to print to screen.
::
:: -m Filename = write the interpreter Macro to Filename.
:: Use con to print to screen.
::
:: -t = Trace mode: Show op address/value, memory address/value
:: each cycle.
::
:: -# Count = Enables # op: Show current state. Count specifies the number
:: of values to display before and after the current address.
:: BUG ALERT: Some array values may not display properly if
:: Count > 0 and array members are swapped out to disk. This is
:: never a problem if -a is undefined.
::
:: -p = Parse only.
::
:: -c Count = Code memory (default = 100). Maximum amount of code allowed
:: to reside in memory at one time. Unlimited if undefined.
:: Excess code is swapped out to disk.
::
:: -a Count = Array memory (default = unlimited). Maximum number of array
:: members allowed to reside in memory at one time. Unlimited
:: if undefined. Excess array members are swapped out to disk.
::
:: -l Count = Limit the number of execution cycles to Count.
:: Ignored if -s enabled. Default is no limit (undefined).
::
:: The memory array consists of unsigned bytes. Increment and decrement
:: operations simply wrap when the limits are exceeded unless -eo is specified.
::
:: The memory array is unbounded both to the left and right. If -em is specified
:: then the array is unbounded to the right only.
::
:: In theory, the code pointer can range from 0 to 2147483647,
:: and the memory pointer can range from -2147483648 to 2147483647.
:: But performance will become unbearably long before those limits are
:: reached.
::
:: BF.BAT can only read input from a file supplied as a command line option, or
:: the keyboard. Input will fail if data is piped into BF.BAT or if stdin is
:: redirected to a file.
::
:: During keyboard input, the <Enter> key is read as <CR>. All other inputs are
:: normal. Any byte value (except 0x00) may be entered by holding down the <Alt>
:: key and entering a decimal code on the numeric keypad. The only way to enter
:: <LF> is via <Alt> and the numeric keypad.
::
:: This code was written by Dave Benham (aka dbenham)
:: with major contributions from Antonio Perez Ayala (aka Aacini),
:: and important suggestions for memory management from einstein1969.
::
:: Development efforts can be traced at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=5751
@echo off
:: Rentry point when running the bf program
if "%~1" equ ":run" ( rem
%bfInterpreter%
) %input%
:: Clear environment except for critical standard values
setlocal disableDelayedExpansion
for /f "eol== delims==" %%V in ('set^|findstr /rc:"^[^=]*!"') do set "%%V="
set "preserve= TEMP TMP PATH PATHEXT COMSPEC PRESERVE "
setlocal enableDelayedExpansion
for /f "eol== delims==" %%V in ('set') do (
if defined %%V if "!preserve: %%V =!" equ "!preserve!" set "%%V="
)
set "preserve="
:: Validate parameters
if "%~1" equ "" >&2 echo Usage: %~N0 filename.ext&exit /b 1
if not exist "%~1" >&2 echo File not found: %1&exit /b 1
:: Define options
set options=-d:"" -s: -z: -e:"" -m:"" -ee: -eo: -em: -ea: -t: -#:"" -p: -i:"" -c:100 -a:"" -l:""
:: Set option defaults
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:loop Parse the option arguments
if not "%~2"=="" (
set "test=!options:*%~2:=! "
if "!test!"=="!options! " (
echo Error: Invalid option %~2
exit /b 1
) else if "!test:~0,1!"==" " (
set "%~2=1"
) else (
set "%~2=%~3"
shift /2
)
shift /2
goto :loop
)
:: Begin macro defnitions --------------
:: Define LF to contain a linefeed (0x0A) character
set ^"LF=^
^" The above empty line is critical - DO NOT REMOVE
:: define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set showTime=(%\n%
for /f "tokens=1-4 delims=:.," %%a in ("^!t1: =0^!"^) do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"%\n%
for /f "tokens=1-4 delims=:.," %%a in ("^!t2: =0^!"^) do set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"%\n%
set /a "tDiff=t2-t1"%\n%
if ^^!tDiff^^! lss 0 set /a tDiff+=24*60*60*100%\n%
set /a "s=tDiff/100, f=tDiff+100"%\n%
echo Elapsed time = ^^!s^^!.^^!f:~-2^^! s%\n%
^)
if defined -ea (
set -eo=1
set -em=1
set -ee=1
)
if defined -eo (
set "inc=set /a m[%%A]+=%%C&if ^!m[%%A]^! gtr 255 >&2 echo ^!LF^!ERROR: Overflow at ip=%%I mp=%%A&exit 1"
set "dec=set /a m[%%A]-=%%C&if ^!m[%%A]^! lss 0 >&2 echo ^!LF^!ERROR: Overflow at ip=%%I mp=%%A&exit 1"
) else (
set inc=set /a "m[%%A]=(m[%%A]+%%C)&255"
set dec=set /a "m[%%A]=(m[%%A]-%%C)&255"
)
if defined -em (
set "leftError=&if ^!mp^! lss 0 >&2 echo ^!LF^!ERROR: Invalid memory access at ip=%%I mp=%%A&exit 1"
)
if defined -t set trace=%\n%
echo c[%%I]=^^!c[%%I]^^! m[%%A]=^^!m[%%A]^^!
if defined -e set ^"setEOF=set /a "m[%%A]=!-e!"^"
if defined -z set eofMacros=1
if defined -i set eofMacros=1
if defined eofMacros (
set "ifNotEOF=if not defined EOF"
set ifSub=else if "^!key:~-1^!" equ "^!SUB^!" (%\n%
endlocal^&endlocal%\n%
set EOF=1%\n%
!setEOF!%\n%
^)
if defined -ee (
set "elsePastEOF= else >&2 echo ^!LF^!ERROR: Read past EOF at ip=%%I mp=%%A&exit 1 "
) else if defined -e (
set "elsePastEOF= else !setEOF! "
)
)
if defined -i (
set ^"getInput=else if "%%B" equ "," ( for /l %%N in (1 1 %%C^) do !ifNotEOF! (%\n%
set "key="%\n%
set /p "key="%\n%
if defined key (set /a "m[%%A]=0x^!key^!"^) else ( !setEOF!%\n%
set EOF=1%\n%
^)%\n%
^)!elsePastEOF!^) ^"
) else (
set ^"getInput=else if "%%B" equ "," (for /l %%N in (1 1 %%C^) do !ifNotEOF! (%\n%
set "key="%\n%
set "CtrlC=1"%\n%
setlocal disableDelayedExpansion%\n%
for /f "delims=" %%K in (%\n%
'xcopy /w "%~f0" "%~f0" 2^^^^^>nul'%\n%
^) do if not defined key (set "key=%%K"^) else set "CtrlC="%\n%
setlocal enableDelayedExpansion%\n%
if defined CtrlC (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=3"%\n%
^) else if "^!key^!" equ "^!line1^!" (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=10"%\n%
^) else if "^!key:~-1^!" equ "^!CR^!" (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=13"%\n%
^) !ifSub! else (%\n%
^>key.bf_tmp echo(^^!key:~-1^^!%\n%
endlocal^&endlocal%\n%
for /f "delims=." %%K in ('findstr /lg:key.bf_tmp *.bf_chr'^) do set "m[%%A]=%%K"%\n%
^)%\n%
^)!elsePastEOF!^) ^"
)
if defined -# (
set #=#
set #Parse=else if "%%b" equ "#" (%\n%
set /a "ip+=1, #Found=1, clr=0"%\n%
^>c[^^!ip^^!].bf_tmp echo #%\n%
^)
if !-#! equ 0 (
set ^"#Exec=else if "%%B" equ "#" (%\n%
set /a next=ip+1%\n%
set "msg="%\n%
^<c[^^!next^^!].bf_tmp set /p "msg="%\n%
echo c[^^!next^^!]=^^!msg^^! m[%%A]=^^!m[%%A]^^!%\n%
^) ^"
) else set ^"#Exec=else if "%%B" equ "#" (%\n%
set /a next=ip+1, m1=mp-!-#!, m2=mp-1, m3=mp+1, m4=mp+!-#!%\n%
set "msg="%\n%
^<c[^^!next^^!].bf_tmp set /p "msg="%\n%
set "msg=c[^!next^!]=^!msg^! mp=%%A: "%\n%
for /l %%N in (^^!m1^^! 1 ^^!m2^^!^) do set "msg=^!msg^!| ^!m[%%N]^! "%\n%
set "msg=^!msg^!< ^!m[%%A]^! >"%\n%
for /l %%N in (^^!m3^^! 1 ^^!m4^^!^) do set "msg=^!msg^! ^!m[%%N]^! |"%\n%
echo ^^!msg^^!%\n%
^) ^"
)
if not defined -s (
set "getCycles=, cycles+=1"
set "getCodePageFaults=, codePageFaults+=1"
set "getArrayStats=, aSize+=1"
set "getArrayPageFaults=, arrayPageFautls+=1"
set showStats=%\n%
^>stats.bf_tmp (echo cycles=^^!cycles^^! codePageFaults=^^!codePageFaults^^!%\n%
echo arraySize=^^!aSize^^! arrayPageFaults=^^!arrayPageFaults^^!^)
if defined -l set getCycles=!getCycles! ^& if ^^!cycles^^! equ !-l! (!showStats!%\n%
exit 0%\n%
^)
)
if defined -c set codePaging=%\n%
if not defined c[%%I] if exist c[%%I].bf_tmp (%\n%
if ^^!cdCnt^^! equ !-c! (%\n%
for /f "delims==" %%A in ('set c[') do set "%%A="%\n%
set cdCnt=0%\n%
)%\n%
set /a cdCnt+=1!getCodePageFaults!%\n%
^<c[%%I].bf_tmp set /p "c[%%I]="%\n%
)
if defined -a (
set arrayPaging=if not defined m[%%A] (%\n%
if ^^!aCnt^^! equ !-a! for /f "tokens=1,2 delims==" %%a in ('set m['^) do (%\n%
^>%%a.bf_tmp echo %%b%\n%
set %%a=%\n%
set aCnt=0%\n%
^)%\n%
if exist m[%%A].bf_tmp (%\n%
^<m[%%A].bf_tmp set /p m[%%A]=%\n%
set /a arrayPageFaults+=1%\n%
^) else set /a m[%%A]=0!getArrayStats!%\n%
set /a aCnt+=1%\n%
^)
) else set "arrayPaging=if not defined m[%%A] set /a m[%%A]=0!getArrayStats!"
:: End macro definition ------------------
:: Create character files if they don't already exist
if not defined -s (
echo ----------------------------
echo Begin Initialization
echo Testing ASCII character files.
)
set "needChars="
for /l %%N in (0 1 255) do for %%F in (%%N.bf_chr) do if "%%~zF" neq "1" set "needChars=1"
if defined needChars (
if not defined -s (
echo Creating ASCII character files...
set "t1=!time!"
)
call :genAllChr
if not defined -s (
set t2=!time!
%showTime%
)
)
:: Parse the input file
if not defined -i goto :skipInput
if not defined -s (
<nul set /p "=Parsing input."
set t1=!time!
)
if not exist "!-i!" >&2 echo ERROR: Input file "!-i!" not found & exit 1
if exist "!-i!\" >&2 echo ERROR: Input file "!-i!" not found & exit 1
copy 0.bf_chr compare.bf_tmp >nul
set /a size=skipStart=1
for %%F in ("!-i!") do set inSize=%%~zF
for /l %%N in (1 1 32) do if !size! lss !inSize! set /a "size*=2" & type compare.bf_tmp >>compare.bf_tmp
fc /b "!-i!" compare.bf_tmp | findstr /rxc:"........: .. .." >diff.bf_tmp
>input.bf_tmp (
for /f "tokens=1,2 delims=:[] " %%A in (diff.bf_tmp) do (
set /a skipEnd=0x%%A
for /l %%N in (!skipStart! 1 !skipEnd!) do echo 00
echo %%B
set /a skipStart=skipEnd+2
if "!skipStart:~-3!" equ "000" <nul set /p "=." >&2
)
for /l %%N in (!skipStart! 1 !inSize!) do echo 00
)
set "input=<input.bf_tmp"
if not defined -s (
set t2=!time!
echo(
%showTime%
)
:skipInput
:: Parse the code and for each op, store the op followed by a number.
:: For [ and ] the number represents the address of the matching loop boundary
:: For all other ops the number represents the repeat count for that op.
:: Optionally treats # as an additional show state op code with constant count.
:: Optimization collapses [-] into special 0 op (no count).
:: Detects if input is not used so getInput can be removed from interpreter loop.
:: Treats loops at beginning or immedieately following ] as comments (ignores them)
if not defined -s (
<nul set /p "=Parsing code."
set "parseProgress=set /a n=(n+1^^)%%500&if ^!n^! equ 0 <nul set /p "=.""
set "t1=!time!"
)
2>nul del c[*.bf_tmp
for %%C in (+ - "<" ">" . "," #) do set "comment%%~C=0"
set /a ip=comment]=-1, sp=count=comment=0, comment[=1
cmd /u /c type %1|find /v ""|findstr "[+\-<>.,[\]!#!]" >src.bf_tmp
for /f %%b in (src.bf_tmp) do ( %parseProgress%
if !comment! gtr 0 (
set /a comment+=!comment%%b!
) else if "!lastOp!" equ "%%b" (
set /a count+=1
) else (
if defined lastOp (
set "test="
if !clr! equ 1 if !lastOp! equ - if !count! equ 1 set /a clr=test=2
if not defined test set clr=0
set /a ip+=1
>c[!ip!].bf_tmp echo !lastOp! !count!
set "lastOp="
)
if "%%b" equ "[" (
if defined comment (set /a comment+=1) else (
set /a "ip+=1, sp+=1, clr=1"
set /a "stack[!sp!]=ip"
)
) else if "%%b" equ "]" for %%s in (!sp!) do (
if !clr! equ 2 (
>c[!stack[%%s]!].bf_tmp echo 0
del c[!ip!].bf_tmp
set /a "ip-=1, sp-=1"
) else (
set /a ip+=1, sp-=1
>c[!ip!].bf_tmp echo ] !stack[%%s]!
>c[!stack[%%s]!].bf_tmp echo [ !ip!
)
set /a "clr=comment=0"
) %#Parse% else (
set "comment="
set "lastOp=%%b"
set /a "count=1"
if "%%b" equ "," set inputRequired=1
)
)
)
if defined lastOp (
set /a ip+=1
>c[!ip!].bf_tmp echo %lastOp% %count%
)
if not defined -s (
set "t2=!time!"
echo(
%showTime%
)
:: Error if unbalanced brackets
if %sp% neq 0 >&2 echo ERROR: Unbalanced brackets&exit /b 1
if defined comment if "%comment%" neq "0" >&2 echo ERROR: Unbalanced brackets&exit /b 1
:: Dump the parsed op codes
if defined -d (for /l %%N in (0 1 !ip!) do (
<c[%%N].bf_tmp set /p "msg="
echo c[%%N]=!msg!
)) >"!-d!"
:: Disable code paging if code length does not exceed -cp
if not defined -c set "-c=!ip!
if !ip! leq !-c! (
set "codePaging="
for /l %%N in (0 1 !ip!) do <c[%%N].bf_tmp set /p "c[%%N]="
)
:: Undefine getInput and/or #Parse if not needed
if not defined inputRequired set "getInput="
if not defined #Found set "#Exec="
:: Define CR to hold <CarriageReturn> for use in input routine
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
:: Define SUB to hold <0x1A>
for /f "delims=" %%A in (26.bf_chr) do set "SUB=%%A"
:: Establish line one of input routine for this locale
set "line1="
for /f "delims=" %%L in (
'echo .^|xcopy /w "%~f0" "%~f0" 2^>nul'
) do if not defined line1 set "line1=%%L"
set "line1=!line1:~0,-1!"
:: Create final interpreter macro
set bfInterpreter=^
set /a "ip=mp=cdCnt=cycles=aCnt=aSize=0"%\n%
for /l %%. in () do for %%I in (^^!ip^^!) do (!codePaging!%\n%
for /f "tokens=1-3" %%A in ("^!mp^! ^!c[%%I]^!") do (%\n%
!arrayPaging!!trace!%\n%
if "%%B" equ "+" (%\n%
!inc!%\n%
) else if "%%B" equ "-" (%\n%
!dec!%\n%
) else if "%%B" equ "0" (%\n%
set "m[%%A]=0"%\n%
) else if "%%B" equ ">" (%\n%
set /a "mp+=%%C"%\n%
) else if "%%B" equ "<" (%\n%
set /a "mp-=%%C"!leftError!%\n%
) else if "%%B" equ "[" (%\n%
if "^!m[%%A]^!" equ "0" set "ip=%%C"%\n%
) else if "%%B" equ "]" (%\n%
if "^!m[%%A]^!" neq "0" set "ip=%%C"%\n%
) else if "%%B" equ "." for /l %%N in (1 1 %%C) do (%\n%
if "^!m[%%A]^!" equ "26" (set /p "=^!SUB^!" ^<nul) else type ^^!m[%%A]^^!.bf_chr%\n%
) !getInput!!#Exec!else (!showStats!%\n%
exit 0%\n%
)%\n%
set /a ip+=1!getCycles!%\n%
)%\n%
)
:: Print out the finalized brainF*** interpreter macro
if defined -m >"!-m!" echo bfInterpreter=!lf!!bfInterpreter:%%=%%%%!
if not defined -s (
echo Initialization complete
echo ============================
set t1=%time%
)
(call )
if defined -p goto :quit
:: Launch the interpreter
cmd /v:on /c "%~f0" :run&&(call )||(call)
set "err=%errolevel%
if not defined -s (
set t2=%time%
echo(
echo ============================
%showTime%
if exist stats.bf_tmp type stats.bf_tmp
)
:quit
del *.bf_tmp
exit /b %err%
:genAllChr
::This code creates 256 1 byte files, one for each possible byte value.
::This is encoded in a macro way to be called asynchronously with start cmd /c
::Teamwork of carlos, penpen, aGerman, dbenham, einstein1969
::Tested under Win7 and XP
setlocal disableDelayedExpansion
set ^"genchr=(^
for /l %%N in (%%A !cnt! 255) do (^
if %%N equ 26 (^
copy /y nul + nul /a 26.bf_chr /a ^>nul^
) else (if %%N geq 35 if %%N leq 126 if %%N neq 61 (^
^<nul set /p "=!ascii:~%%N,1!" ^>%%N.bf_chr^
))^&^
if not exist %%N.bf_chr (^
makecab /d compress=off /d reserveperdatablocksize=26 /d reserveperfoldersize=%%N %%A.tmp %%N.bf_chr ^>nul^&^
type %%N.bf_chr ^| ((for /l %%n in (1 1 38) do pause)^>nul^&findstr "^^" ^>%%N.temp)^&^
^>nul copy /y %%N.temp /a %%N.bf_chr /b^&^
del %%N.temp^
)^
))^&^
del %%A.tmp^"
del /f /q /a *bf.chr >nul 2>&1
set "ascii= #$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
set /a cnt=number_of_processors
if %cnt% lss 1 set cnt=1
if %cnt% gtr 256 set cnt=256
set /a "end=cnt-1"
for /l %%A in (0 1 %end%) do (
type nul >%%A.tmp
if %%A equ %end% (
cmd /q /v:on /c "%genchr%"
) else (
start "" /b cmd /q /v:on /c "%genchr%"
)
)
:genAllChr.check
for /l %%N in (0 1 %end%) do if exist %%N.tmp goto :genAllChr.check
exit /b
Code: Select all
C:\test\bf>bf3 hanoi2.bf -l 3000000 | ansisys
----------------------------
Begin Initialization
Testing ASCII character files.
Parsing code....................................................................
......................................
Elapsed time = 33.46 s
Initialization complete
============================
Press any key to continue . . .
<screen is cleared, and then...>
Towers of Hanoi in Brainf*ck
Written by Clifford Wolf <http://www.clifford.at/bfcpu/>
xXXXXXXXXXXXXXx
xXXXXXXXXXXXXXXXXXx
xXXXXXXXXXXXXXXXXXXXXXx
xXXXXXXXXXXXXXXXXXXXXXXXXXx
xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
----------------------------------- -----------------------------------
xXx
xXXXXXx
-----------------------------------
============================
Elapsed time = 1943.18 s
cycles=3000000 codePageFaults=76849
arraySize=180 arrayPageFaults=
C:\test\bf>
Code: Select all
SET /A .....
Code: Select all
SET /A instructionA, instructionB
Code: Select all
::BF.BAT - BrainF*** interpreter in Batch, dbenham version 5.0
::
:: Usage:
::
:: bf sourceFile [-option [value]]...
::
:: Options
::
:: -i Filename = read Input from file Filename.
::
:: -z = <Ctrl-Z> terminates keyboard input (forces EOF).
::
:: -e Value = EOF value: Sets value read into memory upon End-Of-File.
:: Default is no change to memory.
::
:: -ee = terminate with Error if attempt is made to read past EOF.
::
:: -eo = terminate with Error if +/- results in Overflow.
::
:: -em = terminate with Error if < yields a negative Memory address.
::
:: -ea = terminate with Error on Any fault. Same as -ee -eo -em
::
:: -s = Silent mode. Don't print initialization messages, elapsed
:: times, or run statistics. Also disables the -l option.
::
:: -d Filename = Dump the parsed op codes to Filename.
:: Use con to print to screen.
::
:: -m Filename = write the interpreter Macro to Filename.
:: Use con to print to screen.
::
:: -t = Trace mode: Show op address/value, memory address/value
:: each cycle.
::
:: -# Count = Enables # op: Show current state. Count specifies the number
:: of values to display before and after the current address.
:: BUG ALERT: Some array values may not display properly if
:: Count > 0 and array members are swapped out to disk. This is
:: never a problem if -a is undefined.
::
:: -p = Parse only.
::
:: -c Count = Code memory (default = 100). Maximum amount of code allowed
:: to reside in memory at one time. Unlimited if undefined.
:: Excess code is swapped out to disk.
::
:: -a Count = Array memory (default = unlimited). Maximum number of array
:: members allowed to reside in memory at one time. Unlimited
:: if undefined. Excess array members are swapped out to disk.
::
:: -l Count = Limit the number of execution cycles to Count.
:: Ignored if -s enabled. Default is no limit (undefined).
::
:: The memory array consists of unsigned bytes. Increment and decrement
:: operations simply wrap when the limits are exceeded unless -eo is specified.
::
:: The memory array is unbounded both to the left and right. If -em is specified
:: then the array is unbounded to the right only.
::
:: In theory, the code pointer can range from 0 to 2147483647,
:: and the memory pointer can range from -2147483648 to 2147483647.
:: But performance will become unbearably long before those limits are
:: reached.
::
:: BF.BAT can only read input from a file supplied as a command line option, or
:: the keyboard. Input will fail if data is piped into BF.BAT or if stdin is
:: redirected to a file.
::
:: During keyboard input, the <Enter> key is read as <CR>. All other inputs are
:: normal. Any byte value (except 0x00) may be entered by holding down the <Alt>
:: key and entering a decimal code on the numeric keypad. The only way to enter
:: <LF> is via <Alt> and the numeric keypad.
::
:: This code was written by Dave Benham (aka dbenham)
:: with major contributions from Antonio Perez Ayala (aka Aacini),
:: and einstein1969.
::
:: Development efforts can be traced at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=5751
@echo off
:: Rentry point when running the bf program
if "%~1" equ ":run" ( rem
%bfInterpreter%
) %input%
:: Clear environment except for critical standard values
setlocal disableDelayedExpansion
for /f "eol== delims==" %%V in ('set^|findstr /rc:"^[^=]*!"') do set "%%V="
set "preserve= TEMP TMP PATH PATHEXT COMSPEC PRESERVE "
setlocal enableDelayedExpansion
for /f "eol== delims==" %%V in ('set') do (
if defined %%V if "!preserve: %%V =!" equ "!preserve!" set "%%V="
)
set "preserve="
:: Validate parameters
if "%~1" equ "" >&2 echo Usage: %~N0 filename.ext&exit /b 1
if not exist "%~1" >&2 echo File not found: %1&exit /b 1
:: Define options
set options=-d:"" -s: -z: -e:"" -m:"" -ee: -eo: -em: -ea: -t: -#:"" -p: -i:"" -c:100 -a:"" -l:""
:: Set option defaults
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:loop Parse the option arguments
if not "%~2"=="" (
set "test=!options:*%~2:=! "
if "!test!"=="!options! " (
echo Error: Invalid option %~2
exit /b 1
) else if "!test:~0,1!"==" " (
set "%~2=1"
) else (
set "%~2=%~3"
shift /2
)
shift /2
goto :loop
)
:: Begin macro defnitions --------------
:: Define LF to contain a linefeed (0x0A) character
set ^"LF=^
^" The above empty line is critical - DO NOT REMOVE
:: define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set showTime=(%\n%
for /f "tokens=1-4 delims=:.," %%a in ("^!t1: =0^!"^) do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"%\n%
for /f "tokens=1-4 delims=:.," %%a in ("^!t2: =0^!"^) do set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"%\n%
set /a "tDiff=t2-t1"%\n%
if ^^!tDiff^^! lss 0 set /a tDiff+=24*60*60*100%\n%
set /a "s=tDiff/100, f=tDiff+100"%\n%
echo Elapsed time = ^^!s^^!.^^!f:~-2^^! s%\n%
^)
if defined -ea (
set -eo=1
set -em=1
set -ee=1
)
if defined -eo (
set "inc=over|=(m[^^^!mp^^^!]+=^!count^!)&-256"
set "dec=over|=(m[^^^!mp^^^!]-=^!count^!)&-256"
set overError=%\n%
if ^^!over^^! neq 0 ^>^&2 echo ^^!LF^^!ERROR: Overflow at ip=%%I mp=%%A^&exit 1
) else (
set "inc=m[^^^!mp^^^!]=(m[^^^!mp^^^!]+^!count^!)&255"
set "dec=m[^^^!mp^^^!]=(m[^^^!mp^^^!]-^!count^!)&255"
)
if defined -em (
set leftError=%\n%
if ^^!mp^^! lss 0 ^>^&2 echo ^^!LF^^!ERROR: Invalid memory access at ip=%%I mp=%%A^&exit 1
)
if defined -t set trace=%\n%
echo c[%%I]=^^!c[%%I]^^! m[%%A]=^^!m[%%A]^^!
if defined -e set ^"setEOF=set /a "m[%%A]=!-e!"^"
if defined -z set eofMacros=1
if defined -i set eofMacros=1
if defined eofMacros (
set "ifNotEOF=if not defined EOF"
set ifSub=else if "^!key:~-1^!" equ "^!SUB^!" (%\n%
endlocal^&endlocal%\n%
set EOF=1%\n%
!setEOF!%\n%
^)
if defined -ee (
set "elsePastEOF= else >&2 echo ^!LF^!ERROR: Read past EOF at ip=%%I mp=%%A&exit 1 "
) else if defined -e (
set "elsePastEOF= else !setEOF! "
)
)
if defined -i (
set ^"getInput=else if "%%B" equ "," ( for /l %%N in (1 1 %%C^) do !ifNotEOF! (%\n%
set "key="%\n%
set /p "key="%\n%
if defined key (set /a "m[%%A]=0x^!key^!"^) else ( !setEOF!%\n%
set EOF=1%\n%
^)%\n%
^)!elsePastEOF!^) ^"
) else for %%F in (findstr.exe) do (
set ^"getInput=else if "%%B" equ "," (for /l %%N in (1 1 %%C^) do !ifNotEOF! (%\n%
set "key="%\n%
set "CtrlC=1"%\n%
setlocal disableDelayedExpansion%\n%
for /f "delims=" %%K in (%\n%
'^^^^^""%%~dp$path:Fxcopy.exe" /w "%~f0" "%~f0" 2^^^^^>nul^^^^^"'%\n%
^) do if not defined key (set "key=%%K"^) else set "CtrlC="%\n%
setlocal enableDelayedExpansion%\n%
if defined CtrlC (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=3"%\n%
^) else if "^!key^!" equ "^!line1^!" (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=10"%\n%
^) else if "^!key:~-1^!" equ "^!CR^!" (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=13"%\n%
^) !ifSub! else (%\n%
^>key.bf_tmp echo(^^!key:~-1^^!%\n%
endlocal^&endlocal%\n%
for /f "delims=." %%K in ('^^^^^""%%~$path:F" /lg:key.bf_tmp *.bf_chr^^^^^"'^) do set "m[%%A]=%%K"%\n%
^)%\n%
^)!elsePastEOF!^) ^"
)
if defined -# (
set #=#
set #Parse=else if "%%b" equ "#" (%\n%
if defined lastCmd (%\n%
set /a ip+=1%\n%
^>c[^^!ip^^!].bf_tmp echo S "^^!lastCmd:~0,-1^^!"%\n%
set "lastCmd="%\n%
^)%\n%
set /a "ip+=1, #Found=1, clr=0"%\n%
^>c[^^!ip^^!].bf_tmp echo #%\n%
^)
if !-#! equ 0 (
set ^"#Exec=else if "%%B" equ "#" (%\n%
set /a next=ip+1%\n%
set "msg="%\n%
^<c[^^!next^^!].bf_tmp set /p "msg="%\n%
echo c[^^!next^^!]=^^!msg^^! m[%%A]=^^!m[%%A]^^!%\n%
^) ^"
) else set ^"#Exec=else if "%%B" equ "#" (%\n%
set /a next=ip+1, m1=mp-!-#!, m2=mp-1, m3=mp+1, m4=mp+!-#!%\n%
set "msg="%\n%
^<c[^^!next^^!].bf_tmp set /p "msg="%\n%
set "msg=c[^!next^!]=^!msg^! mp=%%A: "%\n%
for /l %%N in (^^!m1^^! 1 ^^!m2^^!^) do set "msg=^!msg^!| ^!m[%%N]^! "%\n%
set "msg=^!msg^!< ^!m[%%A]^! >"%\n%
for /l %%N in (^^!m3^^! 1 ^^!m4^^!^) do set "msg=^!msg^! ^!m[%%N]^! |"%\n%
echo ^^!msg^^!%\n%
^) ^"
)
if not defined -s (
set "getCycles=, cycles+=1"
set "getCodePageFaults=, codePageFaults+=1"
set "getArrayStats=, aSize+=1"
set "getArrayPageFaults=, arrayPageFautls+=1"
set showStats=%\n%
^>stats.bf_tmp (echo cycles=^^!cycles^^! codePageFaults=^^!codePageFaults^^!%\n%
echo arraySize=^^!aSize^^! arrayPageFaults=^^!arrayPageFaults^^!^)
if defined -l set getCycles=!getCycles! ^& if ^^!cycles^^! equ !-l! (!showStats!%\n%
exit 0%\n%
^)
)
if defined -c set codePaging=%\n%
if not defined c[%%I] if exist c[%%I].bf_tmp (%\n%
if ^^!cdCnt^^! equ !-c! (%\n%
for /f "delims==" %%A in ('set c[') do set "%%A="%\n%
set cdCnt=0%\n%
)%\n%
set /a cdCnt+=1!getCodePageFaults!%\n%
^<c[%%I].bf_tmp set /p "c[%%I]="%\n%
)
if defined -a (
set arrayPaging=if not defined m[%%A] (%\n%
if ^^!aCnt^^! equ !-a! for /f "tokens=1,2 delims==" %%a in ('set m['^) do (%\n%
^>%%a.bf_tmp echo %%b%\n%
set %%a=%\n%
set aCnt=0%\n%
^)%\n%
if exist m[%%A].bf_tmp (%\n%
^<m[%%A].bf_tmp set /p m[%%A]=%\n%
set /a arrayPageFaults+=1%\n%
^) else set /a m[%%A]=0!getArrayStats!%\n%
set /a aCnt+=1%\n%
^)
) else set "arrayPaging=if not defined m[%%A] set /a m[%%A]=0!getArrayStats!"
:: End macro definition ------------------
:: Create character files if they don't already exist
if not defined -s (
echo ----------------------------
echo Begin Initialization
echo Testing ASCII character files.
)
set "needChars="
for /l %%N in (0 1 255) do for %%F in (%%N.bf_chr) do if "%%~zF" neq "1" set "needChars=1"
if defined needChars (
if not defined -s (
echo Creating ASCII character files...
set "t1=!time!"
)
call :genAllChr
if not defined -s (
set t2=!time!
%showTime%
)
)
:: Parse the input file
if not defined -i goto :skipInput
if not defined -s (
<nul set /p "=Parsing input."
set t1=!time!
)
if not exist "!-i!" >&2 echo ERROR: Input file "!-i!" not found & exit 1
if exist "!-i!\" >&2 echo ERROR: Input file "!-i!" not found & exit 1
copy 0.bf_chr compare.bf_tmp >nul
set /a size=skipStart=1
for %%F in ("!-i!") do set inSize=%%~zF
for /l %%N in (1 1 32) do if !size! lss !inSize! set /a "size*=2" & type compare.bf_tmp >>compare.bf_tmp
fc /b "!-i!" compare.bf_tmp | findstr /rxc:"........: .. .." >diff.bf_tmp
>input.bf_tmp (
for /f "tokens=1,2 delims=:[] " %%A in (diff.bf_tmp) do (
set /a skipEnd=0x%%A
for /l %%N in (!skipStart! 1 !skipEnd!) do echo 00
echo %%B
set /a skipStart=skipEnd+2
if "!skipStart:~-3!" equ "000" <nul set /p "=." >&2
)
for /l %%N in (!skipStart! 1 !inSize!) do echo 00
)
set "input=<input.bf_tmp"
if not defined -s (
set t2=!time!
echo(
%showTime%
)
:skipInput
:: Parse the code. Consecutive op codes are coalesced into one op with a count.
:: Optionally treats # as an additional show state op code (withoug coalesce).
:: Optimization collapses [-] into a special clear value op.
:: + - < > [ ] [-] are all converted into an S op followed by a SET /A expression.
:: Consecutive + - and [-] are concatenated into one op. If followed by
:: < > [ or ] then that op is also concatenated, but that is the limit for one op.
:: . and , are stored as themselves, followed by the count.
:: # is stored as itself without a count
:: Detects if input is not used so getInput can be removed from interpreter loop.
:: Treats loops at beginning or immedieately following ] as comments (ignores them)
if not defined -s (
<nul set /p "=Parsing code."
set "parseProgress=set /a n=(n+1^^)%%500&if ^!n^! equ 0 <nul set /p "=.""
set "t1=!time!"
)
2>nul del c[*.bf_tmp
for %%C in (+ - "<" ">" . "," #) do set "comment%%~C=0"
set /a ip=comment]=-1, sp=count=comment=0, comment[=1
cmd /u /c type %1|find /v ""|findstr "[+\-<>.,[\]!#!]" >src.bf_tmp
for /f %%b in (src.bf_tmp) do ( %parseProgress%
if !comment! gtr 0 (
set /a comment+=!comment%%b!
) else if "!lastOp!" equ "%%b" (
set /a count+=1
) else (
if defined lastOp (
set "test="
if !clr! equ 1 if !lastOp! equ - if !count! equ 1 set /a clr=test=2
if not defined test set clr=0
if "!lastOp!" equ "+" (
set "lastCmd=!lastCmd!%inc%,"
) else if "!lastOp!" equ "-" (
set "lastCmd=!lastCmd!!delim!%dec%,"
) else (
set /a ip+=1
if "!lastOp!" equ ">" (
>c[!ip!].bf_tmp echo S "!lastCmd!mp+=!count!"
) else if "!lastOp!" equ "<" (
>c[!ip!].bf_tmp echo S "!lastCmd!mp-=!count!"
) else (
if defined lastCmd (
>c[!ip!].bf_tmp echo S "!lastCmd:~0,-1!"
set /a ip+=1
)
>c[!ip!].bf_tmp echo !lastOp! !count!
)
set "lastCmd="
)
set "lastOp="
)
if "%%b" equ "[" (
if defined comment (set /a comment+=1) else (
set /a "ip+=1, sp+=1, clr=1"
set /a "stack[!sp!]=ip"
set "stackCmd[!sp!]=!lastCmd!"
set "lastCmd="
)
) else if "%%b" equ "]" for %%s in (!sp!) do (
if !clr! equ 2 (
set "lastCmd=!stackCmd[%%s]!m[^!mp^!]=0,"
set /a "ip-=1, sp-=1"
) else (
set /a ip+=1, sp-=1, count=ip-stack[%%s]
>c[!ip!].bf_tmp echo S "!lastCmd!ip-=^^^!^^^!m[^!mp^!]*!count!"
>c[!stack[%%s]!].bf_tmp echo S "!stackCmd[%%s]!ip+=^^^!m[^!mp^!]*!count!"
set "lastCmd="
)
set /a "clr=comment=0"
) %#Parse% else (
set "comment="
set "lastOp=%%b"
set /a "count=1"
if "%%b" equ "," set inputRequired=1
)
)
)
if defined lastOp (
set /a ip+=1
(
if "!lastOp!" equ "+" (
echo S "!lastCmd!%inc%"
) else if "!lastOp!" equ "-" (
echo S "!lastCmd!%dec%"
) else if "!lastOp!" equ ">" (
echo S "!lastCmd!mp+=!count!"
) else if "!lastOp!" equ "<" (
echo S "!lastCmd!mp-=!count!"
) else (
echo S "!lastCmd:~0,-1!"
echo !lastOp! !count!
)
)>c[!ip!].bf_tmp
) else if defined lastCmd (
set /a ip+=1
>c[!ip!].bf_tmp echo S "!lastCmd:~0,-1!"
)
if not defined -s (
set "t2=!time!"
echo(
%showTime%
)
:: Error if unbalanced brackets
if %sp% neq 0 >&2 echo ERROR: Unbalanced brackets&exit /b 1
if defined comment if "%comment%" neq "0" >&2 echo ERROR: Unbalanced brackets&exit /b 1
:: Dump the parsed op codes
if defined -d (for /l %%N in (0 1 !ip!) do (
<c[%%N].bf_tmp set /p "msg="
echo c[%%N]=!msg!
)) >"!-d!"
:: Disable code paging if code length does not exceed -cp
if not defined -c set "-c=!ip!
if !ip! leq !-c! (
set "codePaging="
for /l %%N in (0 1 !ip!) do <c[%%N].bf_tmp set /p "c[%%N]="
)
:: Undefine getInput and/or #Parse if not needed
if not defined inputRequired set "getInput="
if not defined #Found set "#Exec="
:: Define CR to hold <CarriageReturn> for use in input routine
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
:: Define SUB to hold <0x1A>
for /f "delims=" %%A in (26.bf_chr) do set "SUB=%%A"
:: Establish line one of input routine for this locale
set "line1="
for /f "delims=" %%L in (
'echo .^|xcopy /w "%~f0" "%~f0" 2^>nul'
) do if not defined line1 set "line1=%%L"
set "line1=!line1:~0,-1!"
:: Create final interpreter macro
set bfInterpreter=^
for /f "delims==" %%V in ('set^^^^^|findstr /bv "c[ line1= CR= SUB="') do set "%%V="%\n%
set /a "ip=mp=cdCnt=cycles=aCnt=aSize=over=0"%\n%
for /l %%. in () do for %%I in (^^!ip^^!) do (!codePaging!%\n%
for /f "tokens=1-3" %%A in ("^!mp^! ^!c[%%I]^!") do (%\n%
!arrayPaging!!trace!%\n%
if "%%B" equ "S" (%\n%
set /a "%%C"!overError!!leftError!%\n%
) else if "%%B" equ "." for /l %%N in (1 1 %%C) do (%\n%
if "^!m[%%A]^!" equ "26" (set /p "=^!SUB^!" ^<nul) else type ^^!m[%%A]^^!.bf_chr%\n%
) !getInput!!#Exec!else (!showStats!%\n%
exit 0%\n%
)%\n%
set /a ip+=1!getCycles!%\n%
)%\n%
)
:: Print out the finalized brainF*** interpreter macro
if defined -m >"!-m!" echo bfInterpreter=!lf!!bfInterpreter:%%=%%%%!
if not defined -s (
echo Initialization complete
echo ============================
set t1=%time%
)
(call )
if defined -p goto :quit
:: Launch the interpreter
cmd /v:on /c "%~f0" :run&&(call )||(call)
set "err=%errolevel%
if not defined -s (
set t2=%time%
echo(
echo ============================
%showTime%
if exist stats.bf_tmp type stats.bf_tmp
)
:quit
del *.bf_tmp
exit /b %err%
:genAllChr
::This code creates 256 1 byte files, one for each possible byte value.
::This is encoded in a macro way to be called asynchronously with start cmd /c
::Teamwork of carlos, penpen, aGerman, dbenham, einstein1969
::Tested under Win7 and XP
setlocal disableDelayedExpansion
set ^"genchr=(^
for /l %%N in (%%A !cnt! 255) do (^
if %%N equ 26 (^
copy /y nul + nul /a 26.bf_chr /a ^>nul^
) else (if %%N geq 35 if %%N leq 126 if %%N neq 61 (^
^<nul set /p "=!ascii:~%%N,1!" ^>%%N.bf_chr^
))^&^
if not exist %%N.bf_chr (^
makecab /d compress=off /d reserveperdatablocksize=26 /d reserveperfoldersize=%%N %%A.tmp %%N.bf_chr ^>nul^&^
type %%N.bf_chr ^| ((for /l %%n in (1 1 38) do pause)^>nul^&findstr "^^" ^>%%N.temp)^&^
^>nul copy /y %%N.temp /a %%N.bf_chr /b^&^
del %%N.temp^
)^
))^&^
del %%A.tmp^"
del /f /q /a *bf.chr >nul 2>&1
set "ascii= #$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
set /a cnt=number_of_processors
if %cnt% lss 1 set cnt=1
if %cnt% gtr 256 set cnt=256
set /a "end=cnt-1"
for /l %%A in (0 1 %end%) do (
type nul >%%A.tmp
if %%A equ %end% (
cmd /q /v:on /c "%genchr%"
) else (
start "" /b cmd /q /v:on /c "%genchr%"
)
)
:genAllChr.check
for /l %%N in (0 1 %end%) do if exist %%N.tmp goto :genAllChr.check
exit /b
dbenham wrote: Pipelining operations into one cycle - great idea
It makes a HUGE difference. The triangle is twice as fast on my machine. And hanoi is nearly twice as fast, without bothering to optimize the code page size.
I completely redesigned most of the op codes. Each of the following can be expressed as a single SET /A expression, expressed as an S op code:
+
-
<
>
[
]
[-]
The following can be concatenated indefinitely:
+
-
[-]
Also, the above can be combined with any one of the following:
<
>
[
]
dbenham wrote:Great ideas Antonio - consolidating consecutive identical ops into one op with a count does make a huge performance difference
Aacini wrote:Code: Select all
rem Version 2.1: - Small bug fixed when "*" or "~" characters appear in the input file
rem - Delete *all* variables, excepting the parsed program code and "PATH"
rem - Optimize "[-]" loop as m[%mp%]=0
rem - Optimize "[-]+++..." or "[-]---..." constructs as m[%mp%]=N or m[%mp%]=-N
dbenham wrote:It makes a HUGE difference. The triangle is twice as fast on my machine. And hanoi is nearly twice as fast, without bothering to optimize the code page size.
Code: Select all
c[0]=S "mp+=1"
c[10]=S "mp+=2"
c[11]=S "m[!mp!]=(m[!mp!]+2)&255,mp+=3"
c[12]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=3"
c[13]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=10"
c[14]=S "ip+=^!m[!mp!]*66"
c[15]=S "m[!mp!]=(m[!mp!]-1)&255,ip+=^!m[!mp!]*3"
c[16]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[17]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=1"
c[18]=S "ip-=^!^!m[!mp!]*3"
c[19]=S "mp+=1"
c[1]=S "m[!mp!]=(m[!mp!]+4)&255,ip+=^!m[!mp!]*3"
c[20]=S "ip+=^!m[!mp!]*5"
c[21]=S "m[!mp!]=(m[!mp!]-1)&255,mp-=1"
c[22]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=3"
c[23]=. 1
c[24]=S "mp-=2"
c[25]=S "ip-=^!^!m[!mp!]*5"
c[26]=S "mp+=3"
c[27]=S "ip+=^!m[!mp!]*24"
c[28]=S "ip+=^!m[!mp!]*22"
c[29]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[2]=S "mp-=1"
c[30]=S "m[!mp!]=(m[!mp!]+8)&255,ip+=^!m[!mp!]*3"
c[31]=S "mp+=1"
c[32]=S "m[!mp!]=(m[!mp!]+4)&255,mp-=1"
c[33]=S "m[!mp!]=(m[!mp!]-1)&255,ip-=^!^!m[!mp!]*3"
c[34]=S "mp+=1"
c[35]=. 1
c[36]=S "mp-=2"
c[37]=S "ip+=^!m[!mp!]*3"
c[38]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[39]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=1"
c[3]=S "m[!mp!]=(m[!mp!]+8)&255,mp+=1"
c[40]=S "ip-=^!^!m[!mp!]*3"
c[41]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=1"
c[42]=S "ip+=^!m[!mp!]*4"
c[43]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[44]=S "m[!mp!]=(m[!mp!]+10)&255,mp-=2"
c[45]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=1"
c[46]=S "ip-=^!^!m[!mp!]*4"
c[47]=S "mp+=1"
c[48]=. 1
c[49]=S "m[!mp!]=0,mp+=1"
c[4]=S "m[!mp!]=(m[!mp!]-1)&255,ip-=^!^!m[!mp!]*3"
dbenham wrote::shock: Pipelining operations into one cycle - great idea
It makes a HUGE difference. The triangle is twice as fast on my machine. And hanoi is nearly twice as fast, without bothering to optimize the code page size.
I completely redesigned most of the op codes. Each of the following can be expressed as a single SET /A expression, expressed as an S op code:
+
-
<
>
[
]
[-]
The following can be concatenated indefinitely:
+
-
[-]
Also, the above can be combined with any one of the following:
<
>
[
]
The code stored for each cycle is significantly greater. But most cycles pipeline at least 2 operations, so there are significantly fewer lines. The interpreter macro is much smaller (and faster). It only has to define at most 4 operations: S . , # It may have as few as two: S and .
I did not take the time to figure out an optimal code page size - I kept the default at 100. I suspect it should be smaller.
Another optimization I made is to completely wipe out the environment at the start of the interpreter macro, except for the code and a few constants. I had to include the full path to XCOPY and FINDSTR in the macro since PATH is no longer defined. It looks odd that the macro erases itself, but it works.
So here is my version 5. I've done even less testing than before. I won't be surprised if I've managed to break one of the options.
...
Dave Benham
Code: Select all
[ This program prints Sierpinski triangle on 80-column display. ]
>
+ +
+ +
[ < + +
+ +
+ + + +
> - ] >
+ + + + + + + +
[ >
+ + + +
< - ] >
> + + > > > + >
> > + <
< < < < < < < <
< [ - [ - > + <
] > [ - < + > > > . < < ] > > >
[ [
- > + +
+ + + +
+ + [ > + + + +
< - ] >
. < < [ - > + <
] + > [ - > + +
+ + + + + + + + < < + > ] > . [
- ] > ]
] + < < < [ - [
- > + < ] + > [
- < + > > > - [ - > + < ] + + >
[ - < - > ] < <
< ] < < < < ] + + + + + + + + +
+ . + + + . [ - ] < ] + + + + +
* * * * * M a d e * B y : * N Y Y R I K K I * 2 0 0 2 * * * * *
Code: Select all
D:\test\bf>bf4 triangle.bf -c "" -m bf4.txt -d triangle4.txt
----------------------------
Begin Initialization
Testing ASCII character files.
Parsing code.
Elapsed time = 0.38 s
Initialization complete
============================
*
* *
* *
* * * *
* *
* * * *
* * * *
* * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
============================
Elapsed time = 16.40 s
cycles=51913 codePageFaults=
arraySize=107 arrayPageFaults=
Code: Select all
D:\test\bf>bf5 triangle.bf -c "" -m bf5.txt -d triangle5.txt
----------------------------
Begin Initialization
Testing ASCII character files.
Parsing code.
Elapsed time = 0.42 s
Initialization complete
============================
*
* *
* *
* * * *
* *
* * * *
* * * *
* * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
============================
Elapsed time = 7.92 s
cycles=33623 codePageFaults=
arraySize=107 arrayPageFaults=
Code: Select all
bfInterpreter=
set /a "ip=mp=cdCnt=cycles=aCnt=aSize=0"
for /l %%. in () do for %%I in (!ip!) do (
for /f "tokens=1-3" %%A in ("!mp! !c[%%I]!") do (
if not defined m[%%A] set /a m[%%A]=0, aSize+=1
if "%%B" equ "+" (
set /a "m[%%A]=(m[%%A]+%%C)&255"
) else if "%%B" equ "-" (
set /a "m[%%A]=(m[%%A]-%%C)&255"
) else if "%%B" equ "0" (
set "m[%%A]=0"
) else if "%%B" equ ">" (
set /a "mp+=%%C"
) else if "%%B" equ "<" (
set /a "mp-=%%C"
) else if "%%B" equ "[" (
if "!m[%%A]!" equ "0" set "ip=%%C"
) else if "%%B" equ "]" (
if "!m[%%A]!" neq "0" set "ip=%%C"
) else if "%%B" equ "." for /l %%N in (1 1 %%C) do (
if "!m[%%A]!" equ "26" (set /p "=!SUB!" <nul) else type !m[%%A]!.bf_chr
) else (
>stats.bf_tmp (echo cycles=!cycles! codePageFaults=!codePageFaults!
echo arraySize=!aSize! arrayPageFaults=!arrayPageFaults!)
exit 0
)
set /a ip+=1, cycles+=1
)
)
Code: Select all
bfInterpreter=
for /f "delims==" %%V in ('set^|findstr /bv "c[ line1= CR= SUB="') do set "%%V="
set /a "ip=mp=cdCnt=cycles=aCnt=aSize=over=0"
for /l %%. in () do for %%I in (!ip!) do (
for /f "tokens=1-3" %%A in ("!mp! !c[%%I]!") do (
if not defined m[%%A] set /a m[%%A]=0, aSize+=1
if "%%B" equ "S" (
set /a "%%C"
) else if "%%B" equ "." for /l %%N in (1 1 %%C) do (
if "!m[%%A]!" equ "26" (set /p "=!SUB!" <nul) else type !m[%%A]!.bf_chr
) else (
>stats.bf_tmp (echo cycles=!cycles! codePageFaults=!codePageFaults!
echo arraySize=!aSize! arrayPageFaults=!arrayPageFaults!)
exit 0
)
set /a ip+=1, cycles+=1
)
)
Code: Select all
c[0]=> 1
c[1]=+ 4
c[2]=[ 7
c[3]=< 1
c[4]=+ 8
c[5]=> 1
c[6]=- 1
c[7]=] 2
c[8]=> 1
c[9]=+ 8
c[10]=[ 15
c[11]=> 1
c[12]=+ 4
c[13]=< 1
c[14]=- 1
c[15]=] 10
c[16]=> 2
c[17]=+ 2
c[18]=> 3
c[19]=+ 1
c[20]=> 3
c[21]=+ 1
c[22]=< 10
c[23]=[ 119
c[24]=- 1
c[25]=[ 30
c[26]=- 1
c[27]=> 1
c[28]=+ 1
c[29]=< 1
c[30]=] 25
c[31]=> 1
c[32]=[ 39
c[33]=- 1
c[34]=< 1
c[35]=+ 1
c[36]=> 3
c[37]=. 1
c[38]=< 2
c[39]=] 32
c[40]=> 3
c[41]=[ 76
c[42]=[ 75
c[43]=- 1
c[44]=> 1
c[45]=+ 8
c[46]=[ 51
c[47]=> 1
c[48]=+ 4
c[49]=< 1
c[50]=- 1
c[51]=] 46
c[52]=> 1
c[53]=. 1
c[54]=< 2
c[55]=[ 60
c[56]=- 1
c[57]=> 1
c[58]=+ 1
c[59]=< 1
c[60]=] 55
c[61]=+ 1
c[62]=> 1
c[63]=[ 70
c[64]=- 1
c[65]=> 1
c[66]=+ 10
c[67]=< 2
c[68]=+ 1
c[69]=> 1
c[70]=] 63
c[71]=> 1
c[72]=. 1
c[73]=0
c[74]=> 1
c[75]=] 42
c[76]=] 41
c[77]=+ 1
c[78]=< 3
c[79]=[ 112
c[80]=- 1
c[81]=[ 86
c[82]=- 1
c[83]=> 1
c[84]=+ 1
c[85]=< 1
c[86]=] 81
c[87]=+ 1
c[88]=> 1
c[89]=[ 110
c[90]=- 1
c[91]=< 1
c[92]=+ 1
c[93]=> 3
c[94]=- 1
c[95]=[ 100
c[96]=- 1
c[97]=> 1
c[98]=+ 1
c[99]=< 1
c[100]=] 95
c[101]=+ 2
c[102]=> 1
c[103]=[ 108
c[104]=- 1
c[105]=< 1
c[106]=- 1
c[107]=> 1
c[108]=] 103
c[109]=< 3
c[110]=] 89
c[111]=< 4
c[112]=] 79
c[113]=+ 10
c[114]=. 1
c[115]=+ 3
c[116]=. 1
c[117]=0
c[118]=< 1
c[119]=] 23
c[120]=+ 5
Code: Select all
c[0]=S "mp+=1"
c[1]=S "m[!mp!]=(m[!mp!]+4)&255,ip+=^!m[!mp!]*3"
c[2]=S "mp-=1"
c[3]=S "m[!mp!]=(m[!mp!]+8)&255,mp+=1"
c[4]=S "m[!mp!]=(m[!mp!]-1)&255,ip-=^!^!m[!mp!]*3"
c[5]=S "mp+=1"
c[6]=S "m[!mp!]=(m[!mp!]+8)&255,ip+=^!m[!mp!]*3"
c[7]=S "mp+=1"
c[8]=S "m[!mp!]=(m[!mp!]+4)&255,mp-=1"
c[9]=S "m[!mp!]=(m[!mp!]-1)&255,ip-=^!^!m[!mp!]*3"
c[10]=S "mp+=2"
c[11]=S "m[!mp!]=(m[!mp!]+2)&255,mp+=3"
c[12]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=3"
c[13]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=10"
c[14]=S "ip+=^!m[!mp!]*66"
c[15]=S "m[!mp!]=(m[!mp!]-1)&255,ip+=^!m[!mp!]*3"
c[16]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[17]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=1"
c[18]=S "ip-=^!^!m[!mp!]*3"
c[19]=S "mp+=1"
c[20]=S "ip+=^!m[!mp!]*5"
c[21]=S "m[!mp!]=(m[!mp!]-1)&255,mp-=1"
c[22]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=3"
c[23]=. 1
c[24]=S "mp-=2"
c[25]=S "ip-=^!^!m[!mp!]*5"
c[26]=S "mp+=3"
c[27]=S "ip+=^!m[!mp!]*24"
c[28]=S "ip+=^!m[!mp!]*22"
c[29]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[30]=S "m[!mp!]=(m[!mp!]+8)&255,ip+=^!m[!mp!]*3"
c[31]=S "mp+=1"
c[32]=S "m[!mp!]=(m[!mp!]+4)&255,mp-=1"
c[33]=S "m[!mp!]=(m[!mp!]-1)&255,ip-=^!^!m[!mp!]*3"
c[34]=S "mp+=1"
c[35]=. 1
c[36]=S "mp-=2"
c[37]=S "ip+=^!m[!mp!]*3"
c[38]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[39]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=1"
c[40]=S "ip-=^!^!m[!mp!]*3"
c[41]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=1"
c[42]=S "ip+=^!m[!mp!]*4"
c[43]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[44]=S "m[!mp!]=(m[!mp!]+10)&255,mp-=2"
c[45]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=1"
c[46]=S "ip-=^!^!m[!mp!]*4"
c[47]=S "mp+=1"
c[48]=. 1
c[49]=S "m[!mp!]=0,mp+=1"
c[50]=S "ip-=^!^!m[!mp!]*22"
c[51]=S "ip-=^!^!m[!mp!]*24"
c[52]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=3"
c[53]=S "ip+=^!m[!mp!]*21"
c[54]=S "m[!mp!]=(m[!mp!]-1)&255,ip+=^!m[!mp!]*3"
c[55]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[56]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=1"
c[57]=S "ip-=^!^!m[!mp!]*3"
c[58]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=1"
c[59]=S "ip+=^!m[!mp!]*13"
c[60]=S "m[!mp!]=(m[!mp!]-1)&255,mp-=1"
c[61]=S "m[!mp!]=(m[!mp!]+1)&255,mp+=3"
c[62]=S "m[!mp!]=(m[!mp!]-1)&255,ip+=^!m[!mp!]*3"
c[63]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[64]=S "m[!mp!]=(m[!mp!]+1)&255,mp-=1"
c[65]=S "ip-=^!^!m[!mp!]*3"
c[66]=S "m[!mp!]=(m[!mp!]+2)&255,mp+=1"
c[67]=S "ip+=^!m[!mp!]*3"
c[68]=S "m[!mp!]=(m[!mp!]-1)&255,mp-=1"
c[69]=S "m[!mp!]=(m[!mp!]-1)&255,mp+=1"
c[70]=S "ip-=^!^!m[!mp!]*3"
c[71]=S "mp-=3"
c[72]=S "ip-=^!^!m[!mp!]*13"
c[73]=S "mp-=4"
c[74]=S "ip-=^!^!m[!mp!]*21"
c[75]=S "m[!mp!]=(m[!mp!]+10)&255"
c[76]=. 1
c[77]=S "m[!mp!]=(m[!mp!]+3)&255"
c[78]=. 1
c[79]=S "m[!mp!]=0,mp-=1"
c[80]=S "ip-=^!^!m[!mp!]*66"
c[81]=S "m[!mp!]=(m[!mp!]+5)&255"
Aacini wrote:The execution of "[" and "]" is performed via an "if" command, not a "set /A" one, so I don't understand what you mean with: "Each of the following can be expressed as a single SET /A expression: + - < > [ ] [-]" or "Also, + - [-] can be combined with any one of the following: < > [ ]". How do you combine a "[" or "]" with "+" or "-" in a single SET /A expression?
dbenham wrote:einstein1969's idea to combine multiple computations into one SET /A statement was another critical step. Especially when I realized I could implement [ and ] as a single SET /A computation.
Code: Select all
) else if "%%B" equ "[" (
if "!m[%%A]!" equ "0" set "ip=%%C"
Code: Select all
set /A "ip+=^!m[!mp!]*3"
Code: Select all
::BF.BAT - BrainF*** interpreter in Batch, dbenham version 6.0
::
:: Usage:
::
:: bf sourceFile [-option [value]]...
::
:: Options
::
:: -i Filename = read Input from file Filename.
::
:: -z = <Ctrl-Z> terminates keyboard input (forces EOF).
::
:: -e Value = EOF value: Sets value read into memory upon End-Of-File.
:: Default is no change to memory.
::
:: -ee = terminate with Error if attempt is made to read past EOF.
::
:: -eo = terminate with Error if +/- results in Overflow.
::
:: -em = terminate with Error if < yields a negative Memory address.
::
:: -ea = terminate with Error on Any fault. Same as -ee -eo -em
::
:: -s = Silent mode. Don't print initialization messages, elapsed
:: times, or run statistics. Also disables the -l option.
::
:: -d Filename = Dump the parsed op codes to Filename.
:: Use con to print to screen.
::
:: -m Filename = write the interpreter Macro to Filename.
:: Use con to print to screen.
::
:: -t = Trace mode: Show op address/value, memory address/value
:: each cycle.
::
:: -# Count = Enables # op: Show current state. Count specifies the number
:: of values to display before and after the current address.
:: BUG ALERT: Some array values may not display properly if
:: Count > 0 and array members are swapped out to disk. This is
:: never a problem if -a is undefined.
::
:: -p = Parse only.
::
:: -c Count = Code memory (default = 100). Maximum amount of code allowed
:: to reside in memory at one time. Unlimited if undefined.
:: Excess code is swapped out to disk.
::
:: -a Count = Array memory (default = unlimited). Maximum number of array
:: members allowed to reside in memory at one time. Unlimited
:: if undefined. Excess array members are swapped out to disk.
::
:: -l Count = Limit the number of execution cycles to Count.
:: Default is no limit (0x80000000).
::
:: The memory array consists of unsigned bytes. Increment and decrement
:: operations simply wrap when the limits are exceeded unless -eo is specified.
::
:: The memory array is unbounded both to the left and right. If -em is specified
:: then the array is unbounded to the right only.
::
:: In theory, the code pointer can range from 0 to 2147483647,
:: and the memory pointer can range from -2147483648 to 2147483647.
:: But performance will become unbearably long before those limits are
:: reached.
::
:: BF.BAT can only read input from a file supplied as a command line option, or
:: the keyboard. Input will fail if data is piped into BF.BAT or if stdin is
:: redirected to a file.
::
:: During keyboard input, the <Enter> key is read as <CR>. All other inputs are
:: normal. Any byte value (except 0x00) may be entered by holding down the <Alt>
:: key and entering a decimal code on the numeric keypad. The only way to enter
:: <LF> is via <Alt> and the numeric keypad.
::
:: This code was written by Dave Benham (aka dbenham)
:: with major contributions from Antonio Perez Ayala (aka Aacini),
:: and einstein1969.
::
:: Development efforts can be traced at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=5751
@echo off
:: Rentry point when running the bf program
if "%~1" equ ":run" (
%_bf_Interpreter%
exit 0
) %_bf_input%
if 1==0 (
:getInput
::
%_bf_getInputSub%
exit /b
)
:: Clear environment except for critical standard values
setlocal disableDelayedExpansion
for /f "eol== delims==" %%V in ('set^|findstr /rc:"^[^=]*!"') do set "%%V="
set "preserve= TEMP TMP PATH PATHEXT COMSPEC PRESERVE "
setlocal enableDelayedExpansion
for /f "eol== delims==" %%V in ('set') do (
if defined %%V if "!preserve: %%V =!" equ "!preserve!" set "%%V="
)
set "preserve="
:: Validate parameters
if "%~1" equ "" >&2 echo Usage: %~N0 filename.ext&exit /b 1
if not exist "%~1" >&2 echo File not found: %1&exit /b 1
:: Define options
set options=-d:"" -s: -z: -e:"" -m:"" -ee: -eo: -em: -ea: -t: -#:"" -p: -i:"" -c:100 -a:"" -l:0x80000000
:: Set option defaults
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:loop Parse the option arguments
if not "%~2"=="" (
set "test=!options:*%~2:=! "
if "!test!"=="!options! " (
echo Error: Invalid option %~2
exit /b 1
) else if "!test:~0,1!"==" " (
set "%~2=1"
) else (
set "%~2=%~3"
shift /2
)
shift /2
goto :loop
)
:: Begin macro defnitions --------------
:: Define LF to contain a linefeed (0x0A) character
set ^"LF=^
^" The above empty line is critical - DO NOT REMOVE
:: define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set showTime=(%\n%
for /f "tokens=1-4 delims=:.," %%a in ("^!t1: =0^!"^) do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"%\n%
for /f "tokens=1-4 delims=:.," %%a in ("^!t2: =0^!"^) do set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"%\n%
set /a "tDiff=t2-t1"%\n%
if ^^!tDiff^^! lss 0 set /a tDiff+=24*60*60*100%\n%
set /a "s=tDiff/100, f=tDiff+100"%\n%
echo Elapsed time = ^^!s^^!.^^!f:~-2^^! s%\n%
^)
if defined -ea (
set -eo=1
set -em=1
set -ee=1
)
if defined -eo (
set "inc=over|=(m[^^^!mp^^^!]+=^!count^!)&-256"
set "dec=over|=(m[^^^!mp^^^!]-=^!count^!)&-256"
set overError=%\n%
if ^^!over^^! neq 0 ^>^&2 echo ^^!LF^^!ERROR: Overflow at ip=%%I mp=%%A^&exit 1
) else (
set "inc=m[^^^!mp^^^!]=(m[^^^!mp^^^!]+^!count^!)&255"
set "dec=m[^^^!mp^^^!]=(m[^^^!mp^^^!]-^!count^!)&255"
)
if defined -em (
set leftError=%\n%
if ^^!mp^^! lss 0 ^>^&2 echo ^^!LF^^!ERROR: Invalid memory access at ip=%%I mp=%%A^&exit 1
)
if defined -t set trace=%\n%
echo c[%%I]=^^!c[%%I]^^! m[%%A]=^^!m[%%A]^^!
if defined -e set ^"setEOF=set /a "m[%%A]=!-e!"^"
if defined -z set eofMacros=1
if defined -i set eofMacros=1
if defined eofMacros (
set "ifNotEOF=if not defined EOF"
set ifSub=else if "^!key:~-1^!" equ "^!SUB^!" (%\n%
endlocal^&endlocal%\n%
set EOF=1%\n%
!setEOF!%\n%
^)
if defined -ee (
set "elsePastEOF= else >&2 echo ^!LF^!ERROR: Read past EOF at ip=%%I mp=%%A&exit 1 "
) else if defined -e (
set "elsePastEOF= else !setEOF! "
)
)
if defined -i (
set ^"getInput=else if "%%B" equ "," ( for /l %%N in (1 1 %%C^) do !ifNotEOF! (%\n%
set "key="%\n%
set /p "key="%\n%
if defined key (set /a "m[%%A]=0x^!key^!"^) else ( !setEOF!%\n%
set EOF=1%\n%
^)%\n%
^)!elsePastEOF!^) ^"
) else for %%F in (findstr.exe) do (
set ^"getInput=else if "%%B" equ "," (%\n%
call :getInput%\n%
^) ^"
set ^"_bf_getInputSub= for %%. in (x^) do for /l %%N in (1 1 %%C^) do !ifNotEOF! (%\n%
set "key="%\n%
set "CtrlC=1"%\n%
setlocal disableDelayedExpansion%\n%
for /f "delims=" %%K in (%\n%
'^^^^^""%%~dp$path:Fxcopy.exe" /w "%~f0" "%~f0" 2^^^^^>nul^^^^^"'%\n%
^) do if not defined key (set "key=%%K"^) else set "CtrlC="%\n%
setlocal enableDelayedExpansion%\n%
if defined CtrlC (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=3"%\n%
^) else if "^!key^!" equ "^!line1^!" (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=10"%\n%
^) else if "^!key:~-1^!" equ "^!CR^!" (%\n%
endlocal^&endlocal%\n%
set "m[%%A]=13"%\n%
^) !ifSub! else (%\n%
^>key.bf_tmp echo(^^!key:~-1^^!%\n%
endlocal^&endlocal%\n%
for /f "delims=." %%K in ('^^^^^""%%~$path:F" /lg:key.bf_tmp *.bf_chr^^^^^"'^) do set "m[%%A]=%%K"%\n%
^)%\n%
^)!elsePastEOF!^"
)
if defined -# (
set #=#
set #Parse=else if "%%b" equ "#" (%\n%
if defined lastCmd (%\n%
set /a ip+=1%\n%
^>c[^^!ip^^!].bf_tmp echo S "^^!lastCmd:~0,-1^^!"%\n%
set "lastCmd="%\n%
^)%\n%
set /a "ip+=1, #Found=1, clr=0"%\n%
^>c[^^!ip^^!].bf_tmp echo #%\n%
^)
if !-#! equ 0 (
set ^"#Exec=else if "%%B" equ "#" (%\n%
set /a next=ip+1%\n%
set "msg="%\n%
^<c[^^!next^^!].bf_tmp set /p "msg="%\n%
echo c[^^!next^^!]=^^!msg^^! m[%%A]=^^!m[%%A]^^!%\n%
^) ^"
) else set ^"#Exec=else if "%%B" equ "#" (%\n%
set /a next=ip+1, m1=mp-!-#!, m2=mp-1, m3=mp+1, m4=mp+!-#!%\n%
set "msg="%\n%
^<c[^^!next^^!].bf_tmp set /p "msg="%\n%
set "msg=c[^!next^!]=^!msg^! mp=%%A: "%\n%
for /l %%N in (^^!m1^^! 1 ^^!m2^^!^) do set "msg=^!msg^!| ^!m[%%N]^! "%\n%
set "msg=^!msg^!< ^!m[%%A]^! >"%\n%
for /l %%N in (^^!m3^^! 1 ^^!m4^^!^) do set "msg=^!msg^! ^!m[%%N]^! |"%\n%
echo ^^!msg^^!%\n%
^) ^"
)
if not defined -s (
set "getCodePageFaults=, codePageFaults+=1"
set "getArrayStats=, aSize+=1"
set "getArrayPageFaults=, arrayPageFautls+=1"
set showStats=%\n%
^>stats.bf_tmp (echo cycles=%%. codePageFaults=^^!codePageFaults^^!%\n%
echo arraySize=^^!aSize^^! arrayPageFaults=^^!arrayPageFaults^^!^)
if "!-l!" neq "0x80000000" set limitStats=%\n%
for %%. in (!-l!^) do (!showStats!%\n%
^)
)
if defined -c set codePaging=%\n%
if not defined c[%%I] if exist c[%%I].bf_tmp (%\n%
if ^^!cdCnt^^! equ !-c! (%\n%
for /f "delims==" %%A in ('set c[') do set "%%A="%\n%
set cdCnt=0%\n%
)%\n%
set /a cdCnt+=1!getCodePageFaults!%\n%
^<c[%%I].bf_tmp set /p "c[%%I]="%\n%
)
if defined -a (
set arrayPaging=if not defined m[%%A] (%\n%
if ^^!aCnt^^! equ !-a! for /f "tokens=1,2 delims==" %%a in ('set m['^) do (%\n%
^>%%a.bf_tmp echo %%b%\n%
set %%a=%\n%
set aCnt=0%\n%
^)%\n%
if exist m[%%A].bf_tmp (%\n%
^<m[%%A].bf_tmp set /p m[%%A]=%\n%
set /a arrayPageFaults+=1%\n%
^) else set /a m[%%A]=0!getArrayStats!%\n%
set /a aCnt+=1%\n%
^)
) else set "arrayPaging=if not defined m[%%A] set /a m[%%A]=0!getArrayStats!"
:: End macro definition ------------------
:: Create character files if they don't already exist
if not defined -s (
echo ----------------------------
echo Begin Initialization
echo Testing ASCII character files.
)
set "needChars="
for /l %%N in (0 1 255) do for %%F in (%%N.bf_chr) do if "%%~zF" neq "1" set "needChars=1"
if defined needChars (
if not defined -s (
echo Creating ASCII character files...
set "t1=!time!"
)
call :genAllChr
if not defined -s (
set t2=!time!
%showTime%
)
)
:: Parse the input file
if not defined -i goto :skipInput
if not defined -s (
<nul set /p "=Parsing input."
set t1=!time!
)
if not exist "!-i!" >&2 echo ERROR: Input file "!-i!" not found & exit 1
if exist "!-i!\" >&2 echo ERROR: Input file "!-i!" not found & exit 1
copy 0.bf_chr compare.bf_tmp >nul
set /a size=skipStart=1
for %%F in ("!-i!") do set inSize=%%~zF
for /l %%N in (1 1 32) do if !size! lss !inSize! set /a "size*=2" & type compare.bf_tmp >>compare.bf_tmp
fc /b "!-i!" compare.bf_tmp | findstr /rxc:"........: .. .." >diff.bf_tmp
>input.bf_tmp (
for /f "tokens=1,2 delims=:[] " %%A in (diff.bf_tmp) do (
set /a skipEnd=0x%%A
for /l %%N in (!skipStart! 1 !skipEnd!) do echo 00
echo %%B
set /a skipStart=skipEnd+2
if "!skipStart:~-3!" equ "000" <nul set /p "=." >&2
)
for /l %%N in (!skipStart! 1 !inSize!) do echo 00
)
set "_bf_input=<input.bf_tmp"
if not defined -s (
set t2=!time!
echo(
%showTime%
)
:skipInput
:: Parse the code. Consecutive op codes are coalesced into one op with a count.
:: Optionally treats # as an additional show state op code (withoug coalesce).
:: Optimization collapses [-] into a special clear value op.
:: + - < > [ ] [-] are all converted into an S op followed by a SET /A expression.
:: Consecutive + - and [-] are concatenated into one op. If followed by
:: < > [ or ] then that op is also concatenated, but that is the limit for one op.
:: . and , are stored as themselves, followed by the count.
:: # is stored as itself without a count
:: Detects if input is not used so getInput can be removed from interpreter loop.
:: Treats loops at beginning or immedieately following ] as comments (ignores them)
if not defined -s (
<nul set /p "=Parsing code."
set "parseProgress=set /a n=(n+1^^)%%500&if ^!n^! equ 0 <nul set /p "=.""
set "t1=!time!"
)
2>nul del c[*.bf_tmp
for %%C in (+ - "<" ">" . "," #) do set "comment%%~C=0"
set /a ip=comment]=-1, sp=count=comment=0, comment[=1
cmd /u /c type %1|find /v ""|findstr "[+\-<>.,[\]!#!]" >src.bf_tmp
for /f %%b in (src.bf_tmp) do ( %parseProgress%
if !comment! gtr 0 (
set /a comment+=!comment%%b!
) else if "!lastOp!" equ "%%b" (
set /a count+=1
) else (
if defined lastOp (
set "test="
if !clr! equ 1 if !lastOp! equ - if !count! equ 1 set /a clr=test=2
if not defined test set clr=0
if "!lastOp!" equ "+" (
set "lastCmd=!lastCmd!%inc%,"
) else if "!lastOp!" equ "-" (
set "lastCmd=!lastCmd!!delim!%dec%,"
) else (
set /a ip+=1
if "!lastOp!" equ ">" (
>c[!ip!].bf_tmp echo S "!lastCmd!mp+=!count!"
) else if "!lastOp!" equ "<" (
>c[!ip!].bf_tmp echo S "!lastCmd!mp-=!count!"
) else (
if defined lastCmd (
>c[!ip!].bf_tmp echo S "!lastCmd:~0,-1!"
set /a ip+=1
)
>c[!ip!].bf_tmp echo !lastOp! !count!
)
set "lastCmd="
)
set "lastOp="
)
if "%%b" equ "[" (
if defined comment (set /a comment+=1) else (
set /a "ip+=1, sp+=1, clr=1"
set /a "stack[!sp!]=ip"
set "stackCmd[!sp!]=!lastCmd!"
set "lastCmd="
)
) else if "%%b" equ "]" for %%s in (!sp!) do (
if !clr! equ 2 (
set "lastCmd=!stackCmd[%%s]!m[^!mp^!]=0,"
set /a "ip-=1, sp-=1"
) else (
set /a ip+=1, sp-=1, count=ip-stack[%%s]
>c[!ip!].bf_tmp echo S "!lastCmd!ip-=^^^!^^^!m[^!mp^!]*!count!"
>c[!stack[%%s]!].bf_tmp echo S "!stackCmd[%%s]!ip+=^^^!m[^!mp^!]*!count!"
set "lastCmd="
)
set /a "clr=comment=0"
) %#Parse% else (
set "comment="
set "lastOp=%%b"
set /a "count=1"
if "%%b" equ "," set inputRequired=1
)
)
)
if defined lastOp (
set /a ip+=1
(
if "!lastOp!" equ "+" (
echo S "!lastCmd!%inc%"
) else if "!lastOp!" equ "-" (
echo S "!lastCmd!%dec%"
) else if "!lastOp!" equ ">" (
echo S "!lastCmd!mp+=!count!"
) else if "!lastOp!" equ "<" (
echo S "!lastCmd!mp-=!count!"
) else (
echo S "!lastCmd:~0,-1!"
echo !lastOp! !count!
)
)>c[!ip!].bf_tmp
) else if defined lastCmd (
set /a ip+=1
>c[!ip!].bf_tmp echo S "!lastCmd:~0,-1!"
)
if not defined -s (
set "t2=!time!"
echo(
%showTime%
)
:: Error if unbalanced brackets
if %sp% neq 0 >&2 echo ERROR: Unbalanced brackets&exit /b 1
if defined comment if "%comment%" neq "0" >&2 echo ERROR: Unbalanced brackets&exit /b 1
:: Dump the parsed op codes
if defined -d (for /l %%N in (0 1 !ip!) do (
<c[%%N].bf_tmp set /p "msg="
echo c[%%N]=!msg!
)) >"!-d!"
:: Disable code paging if code length does not exceed -cp
if not defined -c set "-c=!ip!
if !ip! leq !-c! (
set "codePaging="
for /l %%N in (0 1 !ip!) do <c[%%N].bf_tmp set /p "c[%%N]="
)
:: Undefine getInput and/or #Parse if not needed
if not defined inputRequired set "getInput=" & set "_bf_getInputSub="
if not defined #Found set "#Exec="
:: Define CR to hold <CarriageReturn> for use in input routine
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
:: Define SUB to hold <0x1A>
for /f "delims=" %%A in (26.bf_chr) do set "SUB=%%A"
:: Establish line one of input routine for this locale
set "line1="
for /f "delims=" %%L in (
'echo .^|xcopy /w "%~f0" "%~f0" 2^>nul'
) do if not defined line1 set "line1=%%L"
set "line1=!line1:~0,-1!"
:: Create final interpreter macro
set _bf_Interpreter=^
for /f "delims==" %%V in ('set ^^^^^|findstr /brc:"[^^ ]*=" ^^^^^|findstr /blv "c[ line1= CR= SUB= _bf_getInputSub="') do set "%%V="%\n%
set /a "ip=mp=cdCnt=cycles=aCnt=aSize=over=0"%\n%
for /l %%. in (0 1 !-l!) do for %%I in (^^!ip^^!) do (!codePaging!%\n%
for /f "tokens=1-3" %%A in ("^!mp^! ^!c[%%I]^!") do (%\n%
!arrayPaging!!trace!%\n%
if "%%B" equ "S" (%\n%
set /a "%%C"!overError!!leftError!%\n%
) else if "%%B" equ "." for /l %%N in (1 1 %%C) do (%\n%
if "^!m[%%A]^!" equ "26" (set /p "=^!SUB^!" ^<nul) else type ^^!m[%%A]^^!.bf_chr%\n%
) !getInput!!#Exec!else (!showStats!%\n%
exit 0%\n%
)%\n%
set /a ip+=1%\n%
)%\n%
)!limitStats!
:: Print out the finalized brainF*** interpreter macro
if defined -m >"!-m!" (
echo - - - - - - - - - - - - - - - - - - - - - -
echo _bf_Interpreter=!lf!!_bf_Interpreter:%%=%%%%!
if defined _bf_getInputSub (
echo - - - - - - - - - - - - - - - - - - - - - -
echo _bf_getInputSub=!lf!!_bf_getInputSub:%%=%%%%!
)
echo - - - - - - - - - - - - - - - - - - - - - -
)
if not defined -s (
echo Initialization complete
echo ============================
set t1=%time%
)
(call )
if defined -p goto :quit
:: Launch the interpreter
cmd /v:on /c "%~f0" :run&&(call )||(call)
set "err=%errolevel%
if not defined -s (
set t2=%time%
echo(
echo ============================
%showTime%
if exist stats.bf_tmp type stats.bf_tmp
)
:quit
del *.bf_tmp
exit /b %err%
:genAllChr
::This code creates 256 1 byte files, one for each possible byte value.
::This is encoded in a macro way to be called asynchronously with start cmd /c
::Teamwork of carlos, penpen, aGerman, dbenham, einstein1969
::Tested under Win7 and XP
setlocal disableDelayedExpansion
set ^"genchr=(^
for /l %%N in (%%A !cnt! 255) do (^
if %%N equ 26 (^
copy /y nul + nul /a 26.bf_chr /a ^>nul^
) else (if %%N geq 35 if %%N leq 126 if %%N neq 61 (^
^<nul set /p "=!ascii:~%%N,1!" ^>%%N.bf_chr^
))^&^
if not exist %%N.bf_chr (^
makecab /d compress=off /d reserveperdatablocksize=26 /d reserveperfoldersize=%%N %%A.tmp %%N.bf_chr ^>nul^&^
type %%N.bf_chr ^| ((for /l %%n in (1 1 38) do pause)^>nul^&findstr "^^" ^>%%N.temp)^&^
^>nul copy /y %%N.temp /a %%N.bf_chr /b^&^
del %%N.temp^
)^
))^&^
del %%A.tmp^"
del /f /q /a *bf.chr >nul 2>&1
set "ascii= #$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
set /a cnt=number_of_processors
if %cnt% lss 1 set cnt=1
if %cnt% gtr 256 set cnt=256
set /a "end=cnt-1"
for /l %%A in (0 1 %end%) do (
type nul >%%A.tmp
if %%A equ %end% (
cmd /q /v:on /c "%genchr%"
) else (
start "" /b cmd /q /v:on /c "%genchr%"
)
)
:genAllChr.check
for /l %%N in (0 1 %end%) do if exist %%N.tmp goto :genAllChr.check
exit /b