BasinC Compiler Tool
At present, no compiler can compile every detail of Sinclair BASIC. The subject still requires considerable research and development, so the available options are limited. BasinC currently provides two compiler modes.
Compiler modes
Machine Coder Native
This mode can compile 48K programs only. It offers a high level of compatibility, but usually provides a speed improvement of approximately two to four times. It has no additional settings.
ZX Basic-Direct
This mode is available when zxbc-direct.exe is present in the external/ directory beneath the BasinC installation directory. It is based on Boriel's Basic compiler, adapted to work with BasinC.
Boriel's Basic is a Sinclair BASIC-like language, but it is not compatible with Sinclair BASIC. Apart from very simple programs, it cannot compile standard Sinclair BASIC source code without adjustments. Work on this compiler is ongoing; for programs it can compile successfully, it can provide speed improvements of up to approximately ten times.
Settings tab
The Settings tab contains the options for the selected compiler mode.
Target
- Start address: specifies the memory address at which the compiled program is placed.
- Optimization: Balanced makes an automatic compromise between speed and size. Speed prioritizes execution speed, while Size prioritizes a smaller output.
- Aggressive: attempts to walk through the code and remove lines that appear to be unused. This can also remove code that is needed indirectly, so use this option with care.
Enable Jump Tables
Boriel's Basic normally expects commands that refer to other program locations, such as GO TO, GO SUB, and RESTORE, to use absolute line numbers. Computed branch targets are nevertheless one of the most common forms of flow control in Sinclair BASIC. BasinC provides jump tables as a workaround.
If your program uses a computed target such as GO SUB 100+50*X, enable the relevant GO TO/GO SUB and undeclared numeric target options. Enable the RESTORE option as well when your program uses a computed RESTORE target.
Where possible, specify the line-number ranges that may be used. Separate ranges with commas and write each range as a starting and ending line number separated by a hyphen, for example:
110-200, 8000-8100, 9900-9950
If the range fields are empty, all program lines are added to the jump table. Each line included in a jump table uses four bytes of memory.
Variables needing attention and Default Type
Boriel's compiler normally attempts to infer the required type of each variable. In practice, this often produces incorrect output. BasinC therefore defaults numeric values to five-byte FLOAT values.
If you know that a variable can use a specific smaller type, you can change the default. Correct type assignments can provide speed improvements of up to approximately ten times. FLOAT produces the slowest calculations. If you are unsure which type to choose, choose INT at minimum. It provides a signed 16-bit range (-32768 to +32767) and can improve speed by up to three or four times.
Automatic variable-type detection can also be enabled, but it has a low probability of producing an effective result and is not recommended.
Tips for ZX Basic-Direct
1. Array declarations (DIM) must appear before use
Rule: Dimension an array, for example DIM a(10), before its first access in the source code.
Why: Boriel's compiler makes a single pass from the beginning of the source to the end. If an array is referenced before its DIM statement—for example, in an initialization subroutine at line 9000—the compiler may mistake it for a function call and report: 'a' is neither an array nor a function.
Fix: Move all DIM statements to the very top of the program, preferably before line 10.
2. Avoid variable and array name conflicts
Rule: Do not use the same name for a scalar variable and an array. For example, LET a = 5 and DIM a(10) conflict. A scalar and a string variable such as LET a = 5 and LET a$ = "x" also create a conflict.
Why: Sinclair BASIC keeps scalar variables and arrays in separate namespaces. In Boriel's compiler, one identifier cannot represent both a variable and an array.
Fix: BasinC automatically renames conflicting arrays, for example to nary_a. When writing code manually, it is better to use different names for each kind of variable and array.
3. Keep IF ... THEN and loop structures separate
Rule: Do not place NEXT directly after THEN, for example IF x > 0 THEN NEXT f.
Why: In Sinclair BASIC, NEXT is an independent run-time statement. In Boriel's compiler, FOR ... NEXT is a structured statement block. Keep NEXT within a clearly defined FOR ... NEXT structure rather than using it as the result of a one-line THEN branch.
4. Use string slicing for single-character assignments
Rule: To modify one character in a string, use string-slicing syntax:
LET a$(4 TO 4) = "x"
Why: Boriel's compiler interprets a$(4) as an array index, not as a substring slice.
5. Handle dynamic jumps and restores
Rule: When a GO TO, GO SUB, or RESTORE uses a variable or a computed line number, such as GO TO 100 * x or RESTORE 7000 + 10 * lvl, enable the corresponding jump-table options in the compiler settings.
Tip: Restrict the ranges to save memory. For example, use 7000-7300, or combine ranges as 7000-7300,8000-9000. Leave the range fields empty to generate jump tables for the whole program. Each line added to a table uses four bytes.
Compiler Controls tab
Compile compiles the BASIC program using the selected compiler mode.
Run runs the compiled machine-code program.
Revert and keep editing removes the compilation from memory and returns you to the editing state from which you started.
To Bridge sends the compilation to the BasinC Bridge tool. From there, you can direct it to the editor of your choice.
To Tape writes the compiled block directly to tape. Note the compilation start address: the saved block is machine code, not a BASIC program, and still requires a BASIC loader before it can be run.
A basic loader starts with CLEAR set to one less than the compilation address, loads the machine-code block with LOAD "" CODE, and then starts it with RANDOMIZE USR. For example, if the program was compiled at address 32768:
10 CLEAR 32767 20 LOAD "" CODE 32768 30 RANDOMIZE USR 32768
You can save this BASIC loader in the Tape Creator. BasinC does not create the loader automatically.
Close is the only way to end the compiling session. The exact closing procedure depends on the selected compiler, and BasinC will ask you any questions required to complete it.