*******************************************************************************
** VBS output specification                                                  **
**  Portable C output                                                        **
**                                                                           **
**   Copyright (c) 1999 Ryan C. Gordon and Gregory S. Read.                  **
*******************************************************************************

To start:
    Basic modules should be converted to ".c" files. Note capitalization: ".C"
     is NOT the same as ".c" ...

    All modules generated by vbSlacker should #include "BasicLib.h"
     Note the capitalization.

    The mainline should look something like this:

    int main(int __argc, char **__argv, char **__envp)
    {
        __initBasicLib(__argc, __argv, __envp);
        __VBSLACKER_MAINLINE__();
        return(0);          /* !!! What should this REALLY return? */
    }

    __VBSLACKER_MAINLINE__() is a separate function, which will contain
    the user-written BASIC mainline, converted, of course, to C.

Lines:
    Each line of BASIC code should be represented in the C output with the
    #line preprocessor directive.

    ' in test.bas ...          'line 1
    PRINT "this is a line."    'line 2
    x = 5                      'line 3

    // converted C code: this is just a paired-down example conversion...

    #line 2 "test.bas"
    vbp_print("this is a line");
    #line 3 "test.bas"
    x = 5;



Comments:
    Comments should be stripped from the BASIC source file, and should not
    be included in the C output. If someone were to use a "/*" or "*/" in
    their own comments it would confuse the C compiler.


SUBs and FUNCTIONs:
    SUBs and FUNCTIONs in BASIC will convert directly to ANSI C format
    functions. That is to say that the format of the C output will not follow
    K&R-style C function syntax, for example. The BASIC mainline (which does
    NOT land between SUB/END SUB statements) will be fitted into a C void
    function of standard naming (__VBSLACKER_MAINLINE__).


Identifiers:
    Every identifier that we insert in the C output should have at least one
    "_" before it. BASIC identifiers can have underscores in them, but may
    not start with one, and the parser should throw an error if they do. This
    prevents namespace clashing, and (I think) is how actual BASICs function.


Name mangling:
    Refer to name_mangling.txt in the repository (/vbslacker/docs directory)
    for how BASIC API calls should be formatted. End user BASIC identifiers
    should be completely lowercased, but otherwise named identically to their
    BASIC counterpart. The exceptions to this rule are line labels, which
    should be serialized as _line0, _line1, _line2, etc...and C-unfriendly
    characters (like "varname$"), which is also covered in name_mangling.txt...

    Identifiers >= 32 characters in the BASIC code should throw a
    WARNING currently, but compilation should still be attempted. ANSI C
    only considers the first 31 characters of an identifier significant,
    but that's not to say specific compilers won't permit more; perhaps a
    BASIC compiler option to enable/disable this warning for various platforms?


BASIC intrinsic data types:
    Intrinsic data types in BASIC convert to C-style variables directly.
    They are wrapped in typedefs, to guarantee the correct size (so
    __integer is always 16-bits on any given platform, for example. int,
    short, and long are not constant between platforms or compilers.)

    INTEGER     __integer
    LONG        __long
    SINGLE      __single
    DOUBLE      __double
    BOOLEAN     __boolean
    BYTE        __byte


BASIC complex data types:
    !!! more.


Default values:
    Any variable, regardless of scope or type, needs to initialize to a
    default "safe" value. Numeric types default to 0.00, BOOLEAN to FALSE,
    Strings to ("").  Objects to (NULL).  !!! and others. This can be done in 
    the C variable initialize way, as follows:

    DIM x AS INTEGER
      --== becomes ==--
    __integer x = 0;


BASIC arrays:
    !!! more.


GOTOs and Line labels:
    Any line labels in BASIC code will translate like this:

    cheesypoof:
      --becomes--
    __insertLineLabel(_line2);

    GOTO cheesypoof:
      --becomes--
    __jumpLabel(_line2);

    This is all made more complicated by the fact that in any given module,
    the same line label name cannot appear more than once. (since on
    platforms that generate inline assembly for the __insertLineLabel
    macro, this will cause a namespace clash at assembly time.) Therefore,
    "cheesypoof", above, would have to be translated into "_line342" or
    whatever. The parser should keep track of this per module, and should
    increment its counter whenever an __insertLineLabel macro is used. This is
    consistent with how C and BASIC treat line labels internally, since labels
    are never accessible outside their given function.

    The serialization of line labels helps a bunch in the supporting of line
     numbers, however.

    __insertLineLabel is needed in three places:
        - In replacement of user-generated BASIC line labels.
        - Between every line of BASIC code (NOT EVERY FUNCTION, JUST EVERY
          LINE...lines continued with the '_' character still count as one
          line) in functions that contain any mention of ON ERROR or RESUME.
        - The line after a GOSUB statement.

    Note that #line directives should go after the __insertLineLabel command.

    The C-output should NEVER contain C-style line labels or gotos, since they
    aren't portable between platforms (at least, not for our needs).

    When necessary, we must label each separate line of BASIC code. That is:

    Print "hello world!"
    Print "My Name is " + _
          "Mudd."

    would need:

    __insertLineLabel(_line0);
    vbPrint("Hello world!")
    __insertLineLabel(_line1);
    vbPrint("My Name is " + "Mudd.");

    (Note that the vbPrint syntax and the string concatenation are wrong,
     but the label thing is right. The reason for this labelling will
     become clear later.)

Line numbers:
    Line numbers are still valid in vbSlacker, and are serialized along with
     the rest of the line labels. (_line1, _line2, _line3, etc...) These do
     not have ':' after them in the BASIC code like the line labels, however.
     According to MS docs, line numbers MUST start in column #1 to be valid,
     and must be unique by module, but do NOT have to be used in numeric order.

Operators; overview:
    C math operators should NEVER directly be used, as BASIC does all sorts
    or rediculous things with variants and operators. The C operators "++"
    and "--" should definitely never be used in vbs output.
    Most other math (like SIN) is performed through the BASIC API, which is
    abstracted in the normal ways in BASIClib.

Operators; '&':
    String concatenation. !!! more.

Operators; '*':
Operators; '+':
Operators; '-':
Operators; '/':
Operators; '\':
Operators; '^':
Operators; '=':
Operators; "AddressOf":



Operators; IMP:
    a = x IMP y
      --== becomes ==--
    a = __IMP(x, y)


Operators; AND:
Operators; OR:
Operators; NOT:
Operators; XOR:
Operators; AND:
Operators; AND:



Order of operations:
    !!! more.


Overflow:
    If the "check for overflow" option is DISABLED, then output is not altered.
    If overflow checking is enabled, then a conditional must wrap every
    assignment to a numeric.
    !!! more.





Conditionals; IF/ELSE/ELSEIF/ENDIF:
    !!! more.


Conditionals; IF TYPEOF...IS...:
    !!! more.


Conditionals; SELECT CASE:
    !!! more.


Flow control: WHILE/WEND:
    !!! more.


Flow control: DO/LOOP:
    !!! more.


Flow control: DO WHILE/LOOP:
    !!! more.


Flow control: DO UNTIL/LOOP:
    !!! more.


Flow control: DO/LOOP UNTIL:
    !!! more.


Flow control: DO/LOOP WHILE:
    !!! more.


Flow control: FOR/NEXT:
    !!! more.


Calling conventions:
    !!! more.


Return values:
    !!! more.


Cleanup upon return:
    !!! more.


Option Explicit:

OPTION EXPLICIT in the code should set a compiler flag to require the
 declarations of variables in BASIC code. This flag holds true for the entire
 module being parsed.


Global variables:
    !!! more.


Local variables:
    !!! more.


Arrays:
    !!! more.


Range Checking:
    !!! more.


Memory (de)allocation:
    This is always handled inside BASIClib, and user code to allocate memory
     should never be necessary. A garbage collector handles most deallocation.

Pointers:
    Pointers are always cast to BASIC LONGs.
    Currently, the only pointers BASIC has access to directly are function
    pointers, and even their usefulness in the BASIC environment is very
    limited. Nonetheless, this is how we shall support them:

    x = AddressOf myFunction

      --== becomes ==--

    /*
     * (if necessary, a function prototype will be inserted, if the given
     *  function is in the project, but not the current module.)
     */

    x = (__long) ((void *) myFunction);   /* note the lack of "()" ... */

    /* The cast to (void *) is for safety's sake. */


SWAP:
    SWAP should be generated inline by the parser/compiler.

    DIM a AS INTEGER
    DIM b AS INTEGER

    SWAP a, b

     --== becomes ==--

    __integer a = 0;
    __integer b = 0;
    __integer __tmp;

    __tmp = a;
    a = b;
    b = __tmp;

    The above example does not include type and overflow checking.


CHOOSE:
       !!! write this.

GOSUB and RETURN:
    Note that "RETURN" and "RETURN 0" do precisely the same thing, although
    both are acceptable syntax. Just treat them interchangably.

    If a GOSUB or RETURN is encountered, then in that functions' variable
    declaration section, this must appear:

    __GOSUBVARS;

    Any GOSUB statements will translate like this:

    GOSUB buttcrack
      --becomes--
    __doGosub(buttCrack, retLabel);
    __insertLineLabel(retLabel);

        where (buttCrack) is the parameter to a __insertLineLabel() macro
         somewhere in that function, and (retLabel) is the next line of
         BASIC code, denoted by an __insertLineLabel() macro.


    RETURN        ' (or RETURN 0)
      --becomes--
    __doReturn;

    RETURN toMyLabel
      --becomes--
    __doReturnLabel(toMyLabel);


    "RETURN without GOSUB" errors are generated at runtime and are not
    checked by the compiler. I think.


ON ... GOSUB:
!!! These must round!

    x = 3
    On x GOSUB line1, line2, line3
     --== becomes ==--

    __GOSUBSUPPORT;
    __integer x = 0;
    __integer __tmp;

    x = 3;
    __tmp = x;   /* needed in case of function...should run only once. */
    if ((__tmp < 0) || (__tmp > 255))  /* negatives or > 255 are errors. */
        __runtimeError(STATEARGS, ERR_OUT_OF_RANGE);  /* !!! or whatever error... */
    else if ((__tmp == 0) || (__tmp > 3))   /* 3 items in list... */
        __jumpLabel(_line4);
    else if (__tmp == 1)
        __doGosub(_line1, _line4);
    else if (__tmp == 2)
        __doGosub(_line2, _line4);
    else if (tmp == 3)
        __doGosub(_line3, _line4);
    __insertLineLabel(_line4);

    This must be generated INLINE, EVERYTIME, by the parser/compiler.
    The above example does not include type and overflow checking.


ON ... GOTO:
!!! These must round!
    x = 3
    On x GOTO line1, line2, line3
     --== becomes ==--

    __GOSUBSUPPORT;
    __integer x = 0;
    __integer __tmp;

    x = 3;
    __tmp = x;   /* needed in case of function...should run only once. */
    if ((__tmp < 0) || (__tmp > 255))  /* negatives or > 255 are errors. */
        __runtimeError(STATEARGS, ERR_OUT_OF_RANGE);  /* or whatever error... */
    else if ((__tmp == 0) || (__tmp > 3))   /* 3 items in list... */
        __jumpLabel(_line4);
    else if (__tmp == 1)
        __jumpLabel(_line1);
    else if (__tmp == 2)
        __jumpLabel(_line2);
    else if (__tmp == 3)
        __jumpLabel(_line3);
    __insertLineLabel(_line4);

    This must be generated INLINE, EVERYTIME, by the parser/compiler.
    The above example does not include type and overflow checking.


ON ERROR and RESUME statements:
    If an ON ERROR or RESUME statement is encountered, then in that functions'
    variable declaration section, this must appear:

    __ONERRORVARS;

    ...and the first statement following the variable section should be:

    __ONERRORINIT();       /* this is a macro, by the way. */

    ...before every line of BASIC code is an __insertLineLabel(lineX) macro
    that allows us to keep track of where each physical line of BASIC code
    begins and ends.

    ...also before every line of BASIC code is a macro to update the pointers
    of where RESUME and RESUME NEXT commands will go. Like so:

    __setInstructs(zeroLabel, nextLabel);

        Where "zeroLabel" is the label of the line a RESUME 0 command should
        jump to, and "nextLabel" is the label of the line a RESUME NEXT command
        should jump to.

    ON ERROR GOTO label
      --becomes--
    __setOnErrorHandler(label);

    AT EVERY POSSIBLE EXIT POINT FROM THE FUNCTION, including returns and
     dropout at the end, you MUST put:

    __exitCleanupOnError();

    (It's a macro.)  Functions returning prematurely due to the throwing of
     a runtime error automagically clean up their OnError state. But deliberate
     leaving of a function will need to have this macro in it.


ON ERROR RESUME NEXT:
    These follow the rules of ON ERROR above, but come out like this:

    void myFunc(void)
    {
        __ONERRORVARS;
        __ONERRORINIT();
        __setOnErrorHandler(resumeNextLabel);
        /* ...your code... */
        __exitCleanupOnError();
        return;
        __insertResumeNextHandler(resumeNextLabel);
    }

    (resumeNextLabel), of course, would be lineN...

    ...if the only ON ERROR and RESUME command in a given function is a
    ON ERROR RESUME NEXT command, the __insertLineLabel() and
    __setOnErrorHandler() macros do not need to be used between each line of
    BASIC code, but while it will bloat the binary a little, it shouldn't hurt
    anything. I think.

    The __insertResumeNextHandler() macro just sets up a line label and a
    __resumeNext call. This could be effectively duplicated in BASIC code as
    such:

    SUB FEH
        ON ERROR GOTO RESUMENEXTHANDLER
        ' My code...
        EXIT SUB
        RESUMENEXTHANDLER:
        RESUME NEXT
    END SUB

    ...there's a reason we're called vbSLACKER, after all.  :)

    If you have __insertResumeNextHandler(x) as the last line of a function,
     there's no need to put __exitCleanupOnError; after it, since we'll never
     fall out of this end of the function. DO however note the need for it
     two lines above it in the example...


ON ERROR GOTO 0:
    Same as On Error Goto label, but the macro is

    __setOnErrorHandlerOff();

    You don't need to label every line and use __setInstructs(), unless
    there are other RESUME or ON ERROR statements in the functions.


Threading:
    The BASIC API has no direct Thread manipulation routines, but C code
    that is part of vbSlacker has a very well-defined API. Refer to threads.txt
    in the /vbslacker/docs directory for details. BASIClib is thread safe when
    compiled in _REENTRANT mode. Single threaded apps can use the multithreaded
    BASIClib transparently (but with a slight performance hit that the single-
    threaded BASIClib should not have). Multithreaded apps will not link with
    a single-threaded BASIClib.


Debugging code:
    This section has yet to be considered fully, but there will be extra code
    inserted into the C output when debugging support is enabled. The extra
    code will allow for tracing of code flow and variable contents, through
    interprocess communication, but the programs with debug code inserted can
    still execute standalone.
    !!!


Object-oriented details:
    !!! more.
    !!! more subheadings.


vbSlacker extension; Inline C:
    BASIC code compiled by vbSlacker may use this construct:

    _INLINE_CODE
        someCode();
        x += 6;
    _END_INLINE_CODE

    Any code within the _INLINE_CODE and _END_INLINE_CODE line will be
     copied, byte for byte, into the C output file. This code is not checked
     for errors by vbSlacker, and is given, unmolested, to the backend compiler
     for evaluation. Therefore inlined code must be whatever vbSlacker is
     generating from the BASIC source file: C, assembly, machine language, or
     whatever. Inline code is completely out of vbSlacker's hands; it can
     prevent compilation, and drastically screw up an otherwise correctly
     coded BASIC program. Needless to say, this extention is unpublished,
     unsupported, and unrecommended. Furthermore, it may vanish later.
    Since they start with an underscore, the tokens "_INLINE_CODE" and
     "_END_INLINE_CODE" will not be reserved by BASIC, nor will they conflict
     with any user-defined identifiers.


vbSlacker extension; BASIC thread API.
    !!! more.


Command lines:
    (!!!This section is not yet complete)
    gcc -fno-omit-frame-pointer -fasm -finline-functions -Wall
        -DLINUXELF_I386 or -DLINUXAOUT_I386 or -DWIN32_I386
        -D_REENTRANT  (or nothing for single-threaded apps)


/* end of vbs_output.txt ... */

