BrainSub

From Esolang

Jump to: navigation, search

BrainSub is a brainfuck compiler designed to generate efficient executable code for MS-DOS/Windows operating systems. It is also an evolution of brainfuck programming language with several additional features that can be useful to write large programs or to learn programming concepts. BrainSub was created by Antonio Perez Ayala in 2007.

Contents

[edit] General features

BrainSub is a brainfuck esoteric programming language compiler that create .COM files for Intel 32-bits CPU's (i386 to Pentium) with all rules of well-behaved executables for MS-DOS/Windows environments. The generated code is very efficient because the compiler performs several code optimizations, like combine duplicated BF commands in one CPU instruction and choose always the shortest form of each instruction, even for [] cycles in general and [-] cycle in particular. For example, Erik Bosman's Mandelbrot Set Fractal Viewer program takes up 15,729 bytes when compiled in the usual BF way, but BrainSub can generate an equivalent .COM file 9,874 bytes long that run in 43% of original execution time. This program can be reduced in size eliminating duplicated code segments in accordance with BrainSub's philosophy, so the resulting .COM file is 7,407 bytes long that run in just 30% of original execution time. This modification was made based on BrainSub compiler's automatic BF to BS translation.

The available data space for compiled programs is a 64K bytes memory segment and the pointer is a 16-bits register, so it always points to a valid memory location. BrainSub allows to select 8, 16 or 32-bits elements that will be directly processed with corresponding CPU instructions. The compiler provides the two most used Input-Output methods: cooked traditional (ASCII character 10 works as New-Line, End-Of-File returns zero) and raw binary (no change).

BrainSub is also an evolution of brainfuck programming language with a double goal.

[edit] BrainSub for application development

BrainSub compiler offer several programming facilities that allow to write large programs in an easier way, like subroutine support to reduce program size, intrinsic subroutines for very common tasks, and collections of subroutines grouped in source libraries that can be included in a program. All these facilities are based in standard BF features so is always possible to convert a BrainSub program with subroutines into the equivalent plain BF program; the compiler can also do this conversion directly.

BrainSub have also additional features that extends beyond brainfuck's original limits, like recursive subroutines, extended intrinsic subroutines that use a[0] element as index or additional control element for cycles, indexed (array of) subroutines that allow to select and execute one of them via a numeric value, and precompiled object libraries for a more efficient compilation and code generation. BrainSub Object Libraries open the possibility to access several computer resources, like MS-DOS functions, Graphics drawing, Mouse control, or manage Floating point values in 32-bits elements that will be operated via respective 80387 or later FPU floating point instructions.

[edit] BrainSub as learning tool

In second place BrainSub is intended to be an educational project suitable for learn basic programming concepts. Brainfuck's data model is so simple that can be understood in a couple minutes even by people with no programming experience; however, the traditional way to write BF programs is so complicated that becomes a hard task even for experienced users. BrainSub's facility features for program writting allow that a new user can focus their attention in the presented concepts rather than how to write the program; this educational aspect of BrainSub have ample support in it's huge documentation. The user's manual put emphasis on write clear and documented programs by mixing appropriately named subroutines with english words (like IF, THEN, WHILE, etc., which are ignored by the compiler) and to define auxiliary subroutines with the purpose of increment the program's legibility.

BrainSub User's Manual show modular programming basics via step-by-step definition of several subroutines intended for a standard library, beginning with the very basic ones that are successively combined until reach some routines rather advanced. The concepts presented via these subroutines covers from RPN logic for evaluation of arithmetic expressions, relational and logical operators, unsigned and signed numbers, string/number conversions, etc., up to recursion or the definition of scope concept and how is related to the place a subroutine is defined; all these themes are presented with BrainSub example programs.

Several additional themes are introduced with the description of external object libraries, like Operating System services, Mouse driver operation, drawing geometric designs with equations or Fractals with iterative methods, and even musical notation basics. The last part of user's manual describe Floating point format and operations, and how to optimize floating point expressions using the 80-bits wide FPU operations stack instead of 32-bits elements.

[edit] BrainSub features based on standard brainfuck

[edit] Subroutine definition and invocation

To define a subroutine in BrainSub put a left parenthesis and the subroutine name delimited by spaces at both sides, followed by all BF commands that form the subroutine body and a right parenthesis to end the definition. For example:

( INPUT  >+[>,] )
( REWIND <[<]   )
( OUTPUT >>[.>] )

To invoke a subroutine enclose its name in parentheses with no spaces. The commands of the original program must be included in a subroutine with the special name "MAIN". For example:

( MAIN  (INPUT) (REWIND) (OUTPUT) )

The subroutine name can have up to 31 characters long and may contain any character, except :;[](), but can not begin with the first character of any intrinsic subroutine.

[edit] Intrinsic subroutines

These are routines for very common tasks that are defined by the compiler itself. Intrinsic subroutines do not have a sole name, like user defined ones, but a sole format of write them that always include a variable part, usually a number. However, intrinsic subroutines have generic names for reference use only.

Generic name    Intrinsic  Example  Equivalent code

Shift right     (>N)       (>9)     >>>>>>>>>
Shift left      (<N)       (<12)    <<<<<<<<<<<<
Increment       (+N)       (+7)     +++++++
Decrement       (-N)       (-10)    ----------
Move right      (}N)       (}2)     >>[-]<<[>>+<<-]
Move lefft      ({N)       ({4)     <<<<[-]>>>>[<<<<+>>>>-]
Sum right       (}+N)      (}+3)    [>>>+<<<-]
Sum left        ({+N)      ({+2)    [<<+>>-]
Take right      (}-N)      (}-4)    [>>>>-<<<<-]
Take left       ({-N)      ({-3)    [<<<->>>-]
Copy right      (}=N)      (}=1)    >[-]>[-]<<[>+>+<<-]>>[<<+>>-]<<
Copy left       ({=N)      ({=2)    <<[-]<[-]>>>[<<+<+>>>-]<<<(}+3)>>>
Xchg right      (}xN)      (}x2)    (}3) >> ({+2) > ({+1) <<<
Xchg left       ({xN)      ({x3)    ({4) <<< (}+3) < (}+1) >>>>
Load Number     (N)        (125)    > [-] (+125)
Load Character  ('c')      ('A')    > [-] (+65)
Load String     ("str")    ("XYZ")  ('X') ('Y') ('Z') (0)

Intrinsic subroutines that begin with }{ can perform their task over more than one destination element separating any additional target element, relative to the previous one, with colon. For example:

Sum a[p] to elements 4, 8 and 10 placed at its right:

(}+4:4:2)    [>>>>+>>>>+>>+(<10)-]

Xchg a[p] with elements a[p+4], a[p+7] and a[p+9]; an exchange with more than one element is equivalent to rotate target elements:

(}x4:3:2)    (>9)(}1)<<(}+2)<<<(}+3)<<<<(}+4)(>10)({+10)(<10)

[edit] Arithmetic expressions, RPN logic

Reverse Polish Notation (RPN) logic is a method to evaluate arithmetic expressions that do not use parentheses because the operators comes after the operands; for example, (3+5)*(4+6) is written 3 5 + 4 6 + * in RPN. To evaluate BrainSub's operations in RPN logic the elements to the right of current element may be used to obtain the result, but elements to the left must be preserved. One-operand operators just store the result in a[p], but two-operands operators must clear a[p], move p back one position and store there the result; for example: ( ADD [<+>-] < ). The expression (3+5)*(4+6) is evaluated in BrainSub this way: (3) (5) (ADD) (4) (6) (ADD) (MUL); note that Load Number intrinsic subroutine load the number in the next array element. If the position of an operand needs to be adjusted for a certain operation, use "stack" manipulation subroutines.

[edit] BrainSub Standard Library

This is a collection of useful subroutines that covers a wide range of operations. All subroutines of Standard library are developed in BrainSub User's Manual with step-by-step explanations. Auxiliary subroutines are written here in lower-case letters.

[edit] Stack manipulation subroutines

Input   Invocation    Output        Equivalent code (sub. definition)

X Y Z   (DUP)         X Y Z Z       (}=1) >
X Y Z   (DUP2ND)      X Y Z Y       < (}=2) >>
X Y Z   (DUP3RD)      X Y Z X       << (}=3) >>>
X Y Z   (BLOCK2DUP)   X Y Z Y Z     (DUP2ND) (DUP2ND)
X Y Z   (BLOCK3DUP)   X Y Z X Y Z   (DUP3RD) (DUP3RD) (DUP3RD)
X Y Z   (XCHG)        X Z Y         < (}x1) >
X Y Z   (XCHG3RD)     Z Y X         << (}x2) >>
X Y Z   (BLOCK3ROR)   Z X Y         << (}x1:1) >>
X Y Z   (BLOCK3ROL)   Y Z X         << (}x1:1) (}x1:1) >>
X Y Z   (POP)         X Y           [-] <
X Y Z   (POP2ND)      X Z           ({1) <
X Y Z   (POP3RD)      Y Z           (BLOCK3ROL) (POP)
X Y Z   (BLOCK2POP)   X             (POP) (POP)
X Y Z   (BLOCK3POP)                 (POP) (POP) (POP)

[edit] Arithmetic subroutines

Input   Invocation   Output     Equivalent code (sub. definition)

X       (CLX)        0          [-]
X Y     (ADD)        X+Y        ({+1) <
X Y     (SUB)        X-Y        ({-1) <
X Y     (MUL)        X*Y        (0)<[>(DUP3RD)(ADD)<-]>({2)<<
X Y     (POW)        X^Y        (1)<[>(DUP3RD)(MUL)<-]>({2)<<
X Y     (divmod)     Quot Rem   (0)(BLOCK3ROR)(BLOCK2DUP)(X>=Y?)
                                [<(DUP)({-2)<<<+>>(BLOCK2DUP)(X>=Y?)]<(POP)
X Y     (DIV)        X/Y        (DIVMOD) (POP)
X Y     (MOD)        X%Y        (DIVMOD) (POP2ND)

[edit] Relational and Logical subroutines

All subroutines in this section returns a Boolean value: 0 if False, 1 if True. The names of subroutines that evaluate a test always end in question-mark character.

Input   Invocation   Output     Equivalent code (sub. definition)

X       (X!=0?)      B          (}1)>[<+>(CLX)]<
X       (X==0?)      B          (X!=0?) (NOT)              or just (NOT)

X Y     (compare)    Xrem Yrem  (BLOCK2DUP)(AND)[<<->-(BLOCK2DUP)(AND)]<
X Y     (X>Y?)       B          (COMPARE)(POP)(X!=0?)
X Y     (X<Y?)       B          (COMPARE)(POP2ND)(X!=0?)
X Y     (X!=Y?)      B          (COMPARE)(OR)
X Y     (X>=Y?)      B          (X<Y?) (NOT)
X Y     (X<=Y?)      B          (X>Y?) (NOT)
X Y     (X==Y?)      B          (X!=Y?) (NOT)

X       (NOT)        B          (1)<[>(CLX)<(CLX)]>[<+>(CLX)]<
X Y     (OR)         B          (0)(BLOCK3ROR)<[ <+>>(CLX)<(CLX)]
                                              >[<<+>>(CLX)]<<
X Y     (AND)        B          (1)(BLOCK3ROR)(1)<<
                                [>>(CLX)<<(CLX)]>>[<<<(CLX)>>>(CLX)]+<
                                [ >(CLX) <(CLX)]> [<<<(CLX)>>>(CLX)]<<<

[edit] Signed Arithmetic/Relational subroutines

These subroutines manage numbers with sign (positive or negative) in the proper way. All signed versions of previously defined subroutines have an I letter at beginning of its names.

( MAX_UNSIGNED (0) - )

( MAX_SIGNED (MAX_UNSIGNED) (2) (DIV) )

( IX>=0? (MAX_SIGNED) (X<=Y?) )

( IX>0?  (DUP) (MAX_SIGNED) (X<=Y?) (AND) )

( IX<0?  (MAX_SIGNED) (X>Y?) )

( ABS (DUP) IF (IX<0?) THEN [<(}1)>[<+>+]] ENDIF < )

( CHS (DUP) IF (IX>0?)(1)< THEN [<(}1)>[<->-](0)<]
                           ELSE >[<<(ABS)>>(CLX)] ENDIF <(POP) )

The following subroutines also manage signed numbers, but their definitions are too long to show them here: IX>Y?, IX>=Y?, IX<Y?, IX<=Y?, IMUL, IDIV and IMOD.

There are also a couple string conversion subroutines that convert a signed number to string with an optional negative sign or viceversa; they are defined in string conversions subroutines section.

[edit] Character manipulation subroutines

Classification: ISSPACE?, ISCNTRL?, ISPRINT?, ISDIGIT?, ISUPPER?, ISLOWER?, ISALPHA? and ISALNUM?.

Conversions: TOUPPER and TOLOWER.

SCANR and SCANL subroutines move the pointer until find the next or previous non-zero element.

CONCATR and CONCATL subroutines move current character until join it to next or previous string.

[edit] String manipulation subroutines

STRSCANR and STRSCANL find the last or first character of current string.

STRCLEARR and STRCLEARL delete from current element to string end or begin.

STRMOVER and STRMOVEL move current string to right or left one position.

STRCONCATR and STRCONCATL move string until join it to next or previous string.

[edit] String conversions and I/O subroutines

STRTOUPPER and STRTOLOWER convert a string to uppercase or lowercase letters.

STRTONUM and NUMTOSTR convert a string to number or viceversa. STRTOINT and INTTOSTR are signed versions.

WRITE display the current string. WRITELN also advance to new line.

READ read characters until press Enter key; BackSpace key delete last character.

READNUM read a number. READINT is signed version.

[edit] Including source libraries

To use the subroutines of the Standard library file you do not need to copy each desired definition in your program; INCLUDE compiler directive allows to insert, and compile, the whole library file this way: (INCLUDE STANDARD). This feature allows to define large library files with useful values that can be included in any program. For example, BrainSub package includes KEYBOARD library file that define the values returned by all special keys in keyboard, like arrows, function keys, etc., and Ctrl-/Alt- combinations; for instance: ( ESC (27) ) or ( SHIFT_F1 (84) ).

If a subroutine is "small" (its compiled code take up less than 7 bytes, like a value definition) it will not be included in the executable file if that subroutine is not used in a program.

Compiler directives are written with parentheses but no spaces, like subroutine invocations, but are placed at beginning of the program before the first subroutine definition.

[edit] Creating and linking object libraries

A source library can be precompiled to generate an Object library that allow a more efficient compilation because the compiler can take from it (link) just the subroutines a program needs, even if they are not "small" ones. To generate an object library use /L compiler switch.

To use the subroutines of an object library use LINK compiler directive this way: (LINK OBJLIB). This directive(s) must be placed in a program before INCLUDE directive(s).

[edit] BrainSub features beyond standard brainfuck

All BrainSub features presented up to now are compatible with standard brainfuck definition, so the equivalent plain BF program can be obtained by replacing all subroutine invocations by its equivalent code. The features presented from this section on are not compatible anymore, so any program that use them must be compiled with BrainSub compiler only.

[edit] Recursive subroutines

Because the first element of a subroutine definition is the subroutine name, after the name this subroutine can be called in a recursive invocation. An executable file created by BrainSub have a stack space of 1K bytes that is enough for deep recursive invocations. BrainSub User's Manual describe the structure and use of recursive subroutines and show a small example: factorial of a number.

( !                     $FACTORIAL
    IF (DUP) THEN       $IF N>0 THEN
       (1) <            $(set Else-Flag, reselect Condition)
        [               $
        -               $    get N-1
        (!)             $    get (N-1)! (recursive call)
        (MUL)           $    get N*(N-1)! (Condition=0)
        >> (CLX)        $    clear Else-Flag
        <               $    select Condition
        ]               $
    ELSE >              $ELSE  select Else-Flag
        [               $
        ({2)            $    set result=1, Else-Flag=0
        ]               $
    ENDIF <<            $ENDIF  select result
)

[edit] Extended intrinsic subroutines

Several intrinsic subroutines can be written in a special form that allow to use a[0] array element as index for certain operations or as control value for cycles additional to a[p].

Intrinsic       Equivalent code

(>0)            p = p+a[0]
(<0)            p = p-a[0]
(+0)            a[p] = a[p]+a[0]
(-0)            a[p] = a[p]-a[0]
(}+0)           a[p+a[0]] = a[p+a[0]]+a[p]
({+0)           a[p-a[0]] = a[p-a[0]]+a[p]
(}-0)           a[p+a[0]] = a[p+a[0]]-a[p]
({-0)           a[p-a[0]] = a[p-a[0]]-a[p]
(}=0)           a[p+a[0]] = a[p]
({=0)           a[p-a[0]] = a[p]
(}x0)           a[p+a[0]] <=> a[p]
({x0)           a[p-a[0]] <=> a[p]

(<)             p = 0
(>)             p = a[0]
(+)             a[0] = a[0]+1
(-)             a[0] = a[0]-1
({+)            a[0] = a[0]+a[p]
({-)            a[0] = a[0]-a[p]
({=)            a[0] = a[p]
(}=)            a[p] = a[0]
({x)            a[0] <=> a[p]
(}x)            a[0] <=> p

([              while (a[0]) {
])              }

There are also a couple extended intrinsic subroutines that allow efficient Input-Output operations over large blocks of data: (,N) and (.N). An example is shown below.

[edit] Immediate values for subroutines

A subroutine can make good use of extended intrinsic subroutines to perform certain tasks in an easier way with the aid of a[0] element. For example, this subroutine duplicate current element the number of times given by a[0]:

( DUP_N   ([ (DUP) (-) ]) )

To use this subroutine load the desired number of times, copy it to a[0], pop it and then invoke the subroutine, for example:

(12) ({=) (POP) (DUP_N)

BrainSub compiler allows to use this type of subroutines in an easier way including the value intended for a[0] in the invocation itself (Immediate Value) separating it of the subroutine name with a colon, for example: (DUP_N:12). This format can also be used to describe the value a subroutine require in a[0], if any. For example: (DUP_N:Times).

[edit] Indexed subroutines

If the subroutine name is a number from 0 to 255 it is inserted in a special array that allow to invoke any of its elements via an index value stored in a[0]. For example:

( 6 ("This is indexed subroutine 6") )
( 4 ("and this is 4!") )

To invoke an indexed subroutine eliminate the subroutine name in the invocation but preserve the immediate value for the index; for example: (:4). If the index is obtained by another way and placed in a[0], eliminate also the immediate value: (:).

[edit] Scope and subroutines

This concept refers to the zone in a program where a given subroutine can be called, in relation to the place where it was defined.

A "module" is any file that take part in a compilation, like a library file (source or object) or the main program file. All subroutines are "local" to the module where they was defined; this means that if you define a subroutine with same name of a library subroutine by chance, each module will invoke the subroutine it intends to do: its own subroutine.

If there are duplicate names in different libraries, the first linked object subroutine, or the last compiled source subroutine, have precedence over other subroutines of same kind. Compiled source subroutines always supersede linked object ones.

When you write an object library you can put the auxiliary subroutines in a separate file that will be INCLUDE'd; this way those subroutines becomes "private" to your library: they can be called just by your library subroutines. The only "public" subroutines of your library, that can be called by another modules, are the subroutines defined in the main file.

Indexed subroutines are not restricted by source program aspects because they are linked to numeric values, accessibles to any program, so they have "global scope": a certain indexed subroutine is the same in any part of the program, so do not matters in wich program module it was defined or invoked.

[edit] Additional features external to BrainSub

BrainSub Compiler Educative Project is work in progress. The documentation describe several object libraries currently under construction that allow a BrainSub program have access to several computer resources. This is the list of currently planned object libraries.

  • EXTENDED: This library provides subroutines with slightly more advanced operations than those of Standard library, like bitwise operators, extended string scan/replace, and pack/unpack bytes to/from elements larger than 8-bits.
  • MS-DOS: Provides links to several DOS service functions (INT 21H).
  • SOUND: Subroutines to generate tones, standard frequencies for notes, duration of notes with standard tempo, and playing melodies.
  • VIDEO: Manage cursor position, standard text colors, scroll screen windows and switch screen contents to several video pages.
  • GRAPHIC: This library use video subroutine V_SET_DOT (INT 10H, Fun 0CH) as the cornerstone to develop a series of graphic subroutines: LINE, BOX, Polygons, Turtle Graphics, etc., up to draw recursive curves and the Mandelbrot Set fractal graphic.
  • MOUSE: Subroutines for basic mouse management that are also combined with some graphic drawing subroutines.
  • FLOAT: Library to evaluate floating point expressions in 32-bits elements and optimize expressions using the FPU stack registers.

Here are the description of an object library that currently have the most complete documentation.

[edit] MS-DOS Library

This library provide links to DOS service functions (INT 21H) that allows a standard access to devices, like keyboard, screen or disk, and provides also some DOS-related values. These are several of the subroutines in this library:

Fun.  Input           Invocation            Result or (action)

0BH-                  (D_KEY_READY?)        a[p] = 255 if key ready, else zero
39H-  p->"DIRNAME"    (D_MAKE_DIR)          if error: < a[p]=0 a[p-1]=error#
3AH-  p->"DIRNAME"    (D_REM_DIR)           if error: < a[p]=0 a[p-1]=error#
3BH-  p->"DIRNAME"    (D_CHANGE_DIR)        if error: < a[p]=0 a[p-1[=error#
3CH-  p->"FILENAME"   (D_CREATE_FILE)       < a[p]=handle, if error: a[p]=0 a[p-1]=error#
3DH-  p->"FILENAME"   (D_OPEN_FILE)         < a[p]=handle, if error: a[p]=0 a[p-1]=error#
3EH-  handle	      (D_CLOSE_FILE)        if error: < a[p]=0 a[p-1]=error#
3FH-  p->handle bytes (D_READ_FROM_FILE)    if ok: >> a[p]=bytes read (they are at p+1)
                                            if error: < a[p]=0 a[p-1]=error#
40H-  p->handle bytes (D_WRITE_TO_FILE)     if ok: >> a[p]=bytes written (from prev. p+3)
                                            if error: < a[p]=0 a[p-1]=error#
41H-  p->"FILENAME"   (D_DELETE_FILE)       if error: < a[p]=0 a[p-1]=error#
44H-  handle          (D_IS_DEVICE?)        > a[p]>0 if handle is device, else a[p]=0
45H-  handle          (D_DUPLICATE_HANDLE)  if ok: > a[p]=newhandle
                                            if error: < a[p]=0 a[p-1]=error#
46H-  p->handle newN  (D_FORCE_DUPLICATE)   if error: < a[p]=0 a[p-1]=error#
                                            (else newN access the same file of handle)
47H-  p->buffer       (D_GET_CURDIR)        p->"D:\CURRENT\DIRECTORY" (19H and 47H)
4CH-  errorlevel      (D_TERMINATE_PROCESS) (end program execution, return errorlevel)
4EH-  p->"PATH\*.*"   (D_FIND_FIRST_FILE)   p->"PATH\FIRSTNAME.EXT", if none: < a[p]=0
4FH-  p->same of 4EH  (D_FIND_NEXT_FILE)    p->"PATH\NEXTNAME.EXT", if no more: < a[p]=0
56H-  p->"OLD" "NEW"  (D_RENAME_FILE)       if error: < a[p]=0 a[p-1]=error#

   -  p->buffer       (D_GET_CMDLINE)       p->"command line"
   -  p->buffer       (D_GET_MYPATH)        p->"D:\MY\PATH\"
   -  p->buffer       (D_GET_ENVIRON)       p->"ENVVAR1" "ENVVAR2" ... (0)

[edit] Example 1: Seek files with a wild-card

>> ("\\PATHNAME\\*.BS") (STRSCANL)      $set p to wild-card (all BS programs)
WHILE (D_FIND_FIRST_FILE)               $seek the first matching file
    [                                   $while another filename was found
    (WRITELN) (STRSCANL)                $show it and return p to original place
    (D_FIND_NEXT_FILE)                  $seek the next matching file
    ]
ENDWHILE

[edit] Example 2: Redirect input inside a program

You can open a disk file and then force a duplicate of it's handle to be STDIN, that is the equivalent operation to redirect it's input but managed inside the program. This way the disk file can be read character by character via the usual input commands and you bypass the hassle of manage memory buffers for disk I/O and all related stuff.

>> ("\\PATHNAME\\FILENAME.TXT")         $load Filename
   (STRSCANL)                           $set p to it
IF (D_OPEN_FILE) THEN                   $open file
    [                                   $ok: handle is in a[p]
    (STDIN) < (D_FORCE_DUPLICATE)       $force dup. of handle to be STDIN
    + [,. (D_KEY_READY?)]               $read ALL bytes and show them
    < (D_CLOSE_FILE)                    $close the file handle
    (CLX)                               $to exit the IF
    ]
NOELSE
ENDIF

[edit] Example 3: Show DOS environment variables

(LINK STDIO)
(LINK MS-DOS)
( MAIN (D_GET_ENVIRON) [ (WRITELN) > ] )

[edit] Additional example: Efficient File Copy

This example use (,0) and (.0) extended Input-Output intrinsic subroutines that process the number of bytes given by a[0] and store the bytes really processed back in a[0]. This example is presented here because is the right place to do it, although it do not use any subroutine of MS-DOS library.

( MAIN
    ('/2')           $Check for /2 compiler switch (16-bits elements)
    < --             $Load 65534 in a[0] (equal to -2 in 16-bits elements)
    >                $Advance p to next ELEMENT (2 BYTES wide)
    (,0)             $Read the first 64K-2 bytes chunk (a[0]=bytes read)
    WHILE NOT EOF
        ([           $While there is another chunk (or part of)...
        (.0) (,0)    $...write it and read the next one
        ])
    ENDWHILE
)

[edit] BrainSub-fkc: a historical/funny note

BrainSub compiler was released the same day of Frida Kahlo's Centennial birthday (July 6, 2007); for this reason is also called BrainSub-fkc.

[edit] External links

[edit] See also

Personal tools