Copyright © 2025-2026 by moshix. All rights reserved.
Welcome to the BASIC/3270BBS interpreter and compiler! This manual will guide you through writing and running BASIC programs on the 3270BBS system.
As of version 2.3.0 of BASIC/3270BBS, programs can be traditional line numbered (e.g. 100 PRINT "Hello, world") or without line numbers and use labels instead, in which case every program must start with a START: label.
From the Extended Menu, press B to enter BASIC/3270BBS . You'll see:
TIMESHARING BASIC/3270BBS V2.9.2
TYPE HELP FOR COMMANDS, BYE TO EXIT
READY
>
- Programs are made of numbered lines (e.g.,
10,20,30) - Lines execute in numerical order
- Type a line number + code to add it to yuor program
- Type
RUNto execute your program - Type
BYEto exit BASIC
| Command | Description |
|---|---|
RUN |
Execute the program |
LIST |
Show all program lines |
LIST 10-50 |
Show lines 10 through 50 |
NEW |
Clear the program from memory |
RENUM |
Renumber lines (10, 20, 30...) |
DELETE 10-50 |
Delete lines 10 through 50 |
| Command | Description |
|---|---|
SAVE "name" |
Save program to file |
LOAD "name" |
Load program from file |
RENAME old.bas new.bas |
Rename a .bas file (both must include .bas) |
EDIT "name" |
Edit file in full-screen editor |
EDIT |
Edit program in memory (no filename) |
BROWSE |
Open file browser to select and edit files |
ERASE "name" |
Delete a single file (.bas, .list, .dat, .idx) |
ERASE pattern |
Delete files matching wildcard (* and ?) |
FILES |
List your files and community programs |
FILES pattern |
List files matching wildcard pattern (* and ?) |
FILES /W |
Wide format: two columns, no timestamps |
FILES /U user |
List shared files from another user |
FILES /C |
List only community files |
FLIST |
List only your files (no community files) |
FLIST pattern |
List your files matching wildcard pattern |
LOAD "user/%file" |
Load a shared file from another user |
Wildcard Patterns: FILES and FLIST support MS-DOS style wildcards:
*matches zero or more characters?matches exactly one character
Examples:
FILES *.bas All .bas files
FILES test* Files starting with "test"
FILES *game* Files containing "game"
FILES ?.bas Single-character .bas files (a.bas, x.bas)
FILES test?.bas test0.bas, test1.bas, testa.bas, etc.
FLIST *.list Your .list files only
FILES *.bas /W Wide format with wildcard filter
RENAME: Both source and target must include the .bas extension to avoid conflicts with .list, .dat, and .idx files. Example: RENAME oldprog.bas newprog.bas
ERASE with wildcards: When the argument contains * or ?, ERASE deletes all matching files in your directory:
*matches zero or more characters?matches exactly one character- Works with .bas, .list, .dat, .idx extensions
- Example:
ERASE pi*.*deletes all files starting with "pi" and any extension - Community files (names starting with
_) cannot be erased
EDIT without a filename: Opens the program currently in memory in the full-screen editor. This is useful when you've loaded a community program and want to modify it. When you save, it creates UNTITLED.bas in your directory.
BROWSE: Opens an interactive file browser that displays all your files and community programs. You can:
- Navigate with F7 (page up) and F8 (page down)
- Type U/C to switch between User and Community files
- Type N/D to sort by Name or Date
- Type any character on a file line to select and open it in the editor
- Type D on a file line to delete it (with confirmation)
- Press F3 to return to BASIC without selecting a file
| Command | Description |
|---|---|
CHECK |
Syntax check program in memory, generate listing file |
VIEW name.list |
View the listing file without clearing program |
EMAIL name.list |
Email the listing as a PDF to your email address |
The CHECK command performs a syntax analysis of the program currently in memory without executing it. It generates a z/OS COBOL-style listing file in your directory named after the program (e.g., myprogram.list). If the program hasn't been saved yet, it uses UNNAMED.list.
What CHECK does:
- Validates syntax of each line
- Identifies syntax errors without running the program
- Detects potential problems and issues warnings
- Builds a variable cross-reference (where each variable is defined and used)
- Creates a data dictionary (all variables and arrays)
- Calculates program statistics
Warnings Detected:
- Loop without SLEEP: FOR/NEXT, WHILE/WEND, or backward GOTO jumps without a
SLEEPstatement may trigger the loop detector or execution time termination - Overly complex lines: Lines with 3+ statements separated by colons are flagged as complex
- Very long lines: Lines exceeding 120 characters are flagged for simplification
- Insufficient comments: Programs with less than 1 REM statement per 10 lines of code receive a program-level warning
Example usage:
10 REM MY PROGRAM
20 LET X = 10
30 PRINT "Value is: "; X
40 END
CHECKOutput:
CHECKING PROGRAM...
NO ERRORS OR WARNINGS FOUND
LISTING SAVED TO myprogram.list
USE VIEW myprogram.list TO SEE FULL LISTING
The VIEW command opens .list files in the editor for viewing. Unlike LOAD or EDIT, it does not clear the program from memory.
Restrictions:
- Only works with
.listextension files - Opens in read-only mode
- Program in memory is preserved
Example:
VIEW myprogram.list
The EMAIL command sends a .list file as a PDF attachment to your registered email address. It uses the same email controls and daily limits as other BBS email features.
Requirements:
- Must have an email address set in your profile
- Daily email limit applies (admin bypass available)
- SendGrid must be configured on the server
The PDF includes:
- Professional header with BBS name and date
- Full listing content in fixed-width Courier font
- Syntax highlighting for errors (red) and warnings (orange)
- Section headers highlighted for cross-reference, data dictionary etc.
Example:
EMAIL myprogram.list
Output:
GENERATING PDF...
SENDING EMAIL TO user@example.com...
EMAIL SENT SUCCESSFULLY
LISTING myprogram.list EMAILED TO user@example.com
Error Messages:
?NO EMAIL ADDRESS IN YOUR PROFILE- Set email in profile settings?DAILY EMAIL LIMIT REACHED- Wait until tomorrow?FILE NOT FOUND- Run CHECK first to generate the listing
The .list file is formatted like a mainframe z/OS COBOL compiler listing:
================================================================================
3270BBS TIMESHARING BASIC COMPILER LISTING
================================================================================
DATE: 25 DEC 2025 14:30:45 USER: MOSHIX
SOURCE: (IN MEMORY)
================================================================================
S O U R C E L I S T I N G
--------------------------------------------------------------------------------
LINE STMT SOURCE TEXT
--------------------------------------------------------------------------------
10 1 REM MY PROGRAM
20 2 LET X = 10
30 3 PRINT "Value is: "; X
================================================================================
E R R O R A N D W A R N I N G S U M M A R Y
================================================================================
ERRORS:
LINE MESSAGE
---- -------
(NO ERRORS)
WARNINGS:
LINE MESSAGE
---- -------
(NO WARNINGS)
TOTAL ERRORS: 0 TOTAL WARNINGS: 0
================================================================================
V A R I A B L E C R O S S - R E F E R E N C E
================================================================================
VARIABLE TYPE DEFINED REFERENCED
--------------------------------------------------------------------------------
X NUMERIC 20 30
================================================================================
D A T A D I C T I O N A R Y
================================================================================
NAME TYPE DIM SIZE DESCRIPTION
--------------------------------------------------------------------------------
X NUMERIC - Simple variable
================================================================================
P R O G R A M S T A T I S T I C S
================================================================================
SOURCE LINES: 3
STATEMENTS: 3
TOTAL SIZE: 54 bytes
ARRAYS DEFINED: 0
ARRAY MEMORY: 0 elements allocated
================================================================================
E N D O F L I S T I N G
================================================================================
The system includes a collection of shared example programs that all users can access. These programs are stored in the basic/community/ directory and have filenames starting with underscore (_).
Using community programs:
FILES- Shows both your files and available community programsFILES /W- Wide format with two columns (no timestamps, saves screen space)LOAD "_example.bas"- Load a community program- Community programs are read-only - you cannot EDIT or ERASE them (including wildcard ERASE)
Users can share programs with each other by naming files with a % prefix. These files are visible to other users but remain read-only.
Creating shared files:
- Save your program with a
%prefix:SAVE "%myprogram.bas" - Only you can modify, save, or erase your own
%files
Accessing other users' shared files:
FILES /U moshix- List shared files from user moshixLOAD "moshix/%example.bas"- Load a shared file from moshix- Shared files are read-only - you can load them but not modify the original
File naming conventions:
_filename- Community files (in basic/community/, read-only)%filename- Shared user files (visible to others, owner can modify)filename- Private user files (only visible to you)
User file restrictions:
- User filenames cannot contain underscores (
_) - This prevents confusion between user files and community files
| Command | Description |
|---|---|
HELP |
Show help information |
VARS |
List all variables |
CLEAR |
Clear teh screen |
BYE / EXIT / QUIT |
Exit BASIC |
10 PRINT "Hello, World!"
20 PRINT "Value is: "; X
30 PRINT A; " + "; B; " = "; A+BYou can add color to your output using the optional COLOR attribute at the end of a PRINT statement:
PRINT expression [; expression ...] [COLOR colorname [modifier]]Colors available:
| Color | Description |
|---|---|
WHITE |
White text |
RED |
Red text |
YELLOW |
Yellow text |
PINK |
Pink/magenta text |
GREEN |
Green text |
BLUE |
Blue text |
TURQUOISE |
Turquoise/cyan text (default) |
Modifiers (optional):
| Modifier | Description |
|---|---|
BLINK |
Blinking text |
REVERSEVIDEO |
Inverted colors (text becomes background) |
Examples (label-based):
START:
PRINT "ALERT!" COLOR RED
PRINT "Success: "; RESULT$ COLOR GREEN
PRINT "WARNING!" COLOR YELLOW BLINK
PRINT "Selected item" COLOR WHITE REVERSEVIDEO
PRINT "Status: "; S; " - "; MSG$ COLOR PINK
ENDNotes:
- The
COLORattribute must appear at the end of the PRINT statement - Without
COLOR, text defaults to turquoise (standard 3270 terminal color) - Colors and modifiers are rendered using 3270 terminal extended attributes
- Not all terminal emulators support all colors or highlighting modes
10 LET X = 10
20 LET NAME$ = "John"
30 X = X + 1 ' LET is optional- Variables ending in
$are strings - Variables wihtout
$are numbers
10 INPUT "Enter your name: ", NAME$
20 INPUT "Enter a number: ", N
30 PRINT "Hello, "; NAME$; "! Your number is "; NBASIC supports both single-line and multi-line IF statements.
10 INPUT "Enter age: ", AGE
20 IF AGE >= 18 THEN PRINT "Adult" ELSE PRINT "Minor"For more complex logic, use block IF with ELSEIF and END IF:
10 INPUT "Enter score: ", SCORE
20 IF SCORE >= 90 THEN
30 PRINT "Grade: A"
40 ELSEIF SCORE >= 80 THEN
50 PRINT "Grade: B"
60 ELSEIF SCORE >= 70 THEN
70 PRINT "Grade: C"
80 ELSE
90 PRINT "Grade: F"
100 END IF
110 PRINT "Done!"Block IF Rules:
IF condition THENon its own line starts a blockELSEIF condition THENprovides additional conditions (optional)ELSEon its own line handles the fallback case (optional)END IF(orENDIF) closes the block - required- Blocks can be nested
Example: Nested IF Blocks
10 INPUT "Enter age: ", AGE
20 IF AGE >= 18 THEN
30 IF AGE >= 65 THEN
40 PRINT "Senior adult"
50 ELSE
60 PRINT "Adult"
70 END IF
80 ELSE
90 PRINT "Minor"
100 END IFComparison operators: =, <>, <, >, <=, >=
10 PRINT "This loops forever!"
20 GOTO 1010 PRINT "Main program"
20 GOSUB 100
30 PRINT "Back in main"
40 END
100 REM Subroutine
110 PRINT "In subroutine"
120 RETURNThe ON statement provides computed branching based on the value of an expression. The expression is evaluated, and program flow jumps to the corresponding line number in the list (1-based index).
ON expression GOTO line1, line2, line3, ...
ON expression GOSUB line1, line2, line3, ...Examples:
10 REM Menu selection example
20 INPUT "Enter choice (1-3): ", CHOICE
30 ON CHOICE GOTO 100, 200, 300
40 PRINT "Invalid choice"
50 GOTO 20
100 PRINT "You chose option 1": GOTO 400
200 PRINT "You chose option 2": GOTO 400
300 PRINT "You chose option 3"
400 END10 REM Device handling with subroutines
20 FOR DEVICE = 1 TO 3
30 ON DEVICE GOSUB 100, 200, 300
40 NEXT DEVICE
50 END
100 PRINT "Handling device 1": RETURN
200 PRINT "Handling device 2": RETURN
300 PRINT "Handling device 3": RETURNBehavior:
- If the expression evaluates to a value less than 1 or greater than the number of line numbers, execution continues to the next line (no jump occurs)
- ON...GOTO jumps to the target line
- ON...GOSUB calls the target as a subroutine (use RETURN to come back)
As an alternative to traditional line-numbered BASIC programs, you can write programs using labels instead of line numbers. This provides a more modern, readable coding style while remaining fully compatible with all BASIC features.
The interpreter automatically detects label-mode based on the first non-empty, non-comment line:
- If the first line starts with a number, the program uses line numbers
- If the first line starts with anything else, the program uses labels
Labels are identifiers followed by a colon at the start of a line:
LabelName:Rules:
- Labels are case-insensitive (
Start:=START:=start:) - Labels must start with a letter or underscore
- Labels can contain letters, digits, and underscores
- Every label-mode program must have a
START:label (execution begins there) - Labels must be unique within a program
START:
PRINT "Enter a number (0 to quit):"
INPUT N
IF N = 0 THEN GOTO Done
PRINT "Square is:"; N * N
GOTO Start
Done:
PRINT "Goodbye!"
ENDIn label-mode programs, use label names instead of line numbers:
GOTO Start
GOSUB CalculateComputed jumps work with labels too:
START:
PRINT "Menu: 1=Add 2=Sub 3=Quit"
INPUT Choice
ON Choice GOTO Add, Sub, Quit
PRINT "Invalid choice"
GOTO Start
Add:
INPUT "A, B: ", A, B
PRINT "Sum:"; A + B
GOTO Start
Sub:
INPUT "A, B: ", A, B
PRINT "Difference:"; A - B
GOTO Start
Quit:
PRINT "Goodbye!"
ENDNote: You cannot mix line numbers and labels in the same ON...GOTO/GOSUB statement.
| Feature | Line Numbers | Labels |
|---|---|---|
| Entry point | First line number | START: label |
| Line format | 10 PRINT "Hello" |
PRINT "Hello" |
| Jump target | GOTO 100 |
GOTO Done |
| Listing format | Shows line numbers | Shows line index |
- New programs - More readable, easier to maintain
- Structured code - Natural fit for subroutines and blocks
- Modern style - Familiar to programmers from other languages
- All BASIC features work identically in both modes
- The
CHECKcommand validates label programs and shows "INDX" instead of "LINE" RENUMcommand is not applicable to label-based programs
START:
FOR I = 1 TO 10
PRINT I
NEXT I
ENDWith STEP (label-based):
START:
FOR I = 10 TO 0 STEP -1
PRINT I
NEXT I
ENDSTART:
X = 1
WHILE X <= 10
PRINT X
X = X + 1
WEND
ENDThe SELECT CASE statement provides a cleaner alternative to multiple IF/ELSEIF chains when testing a single value against multiple options.
10 INPUT "Enter a number (1-5): ", N
20 SELECT CASE N
30 CASE 1
40 PRINT "One"
50 CASE 2, 3
60 PRINT "Two or Three"
70 CASE 4, 5
80 PRINT "Four or Five"
90 CASE ELSE
100 PRINT "Out of range"
110 END SELECT
120 ENDKey features:
- The test expression is evaluated once at SELECT CASE
- Each CASE can have multiple comma-separated values to match
- Only the first matching CASE block executes (no fall-through)
- CASE ELSE is optional and executes if no other CASE matches
- SELECT CASE blocks can be nested
String matching example (label-based):
START:
INPUT "Enter day: ", D$
SELECT CASE D$
CASE "MON", "TUE", "WED", "THU", "FRI"
PRINT "Weekday"
CASE "SAT", "SUN"
PRINT "Weekend"
CASE ELSE
PRINT "Invalid day"
END SELECT
ENDSTART:
DIM SCORES(10) ' 1D array
DIM GRID(5, 5) ' 2D array
DIM NAMES$(20) ' String array
SCORES(1) = 95
NAMES$(0) = "Alice"
ENDAssociative arrays use string keys instead of nurmeic indices. Declare them with curly braces {}:
START:
DIM PHONEBOOK${} ' String associative array
DIM SCORES{} ' Numeric associative array
PHONEBOOK${"Alice"} = "555-1234"
PHONEBOOK${"Bob"} = "555-5678"
SCORES{"Alice"} = 95
SCORES{"Bob"} = 87
PRINT "Alice's phone: "; PHONEBOOK${"Alice"}
PRINT "Bob's score: "; SCORES{"Bob"}
ENDKeys can be variables or expressions:
START:
DIM DATA{}
INPUT "Enter name: ", N$
INPUT "Enter value: ", V
DATA{N$} = V
PRINT N$; " = "; DATA{N$}
ENDThe DEF FN statement allows you to define your own single-expression functions. These are useful for calculations that are used repeatedly throughout your program.
DEF FNname(parameter) = expressionExamples (label-based):
START:
REM Define distance function
DEF FND(X) = SQR(X^2 + Y^2)
X = 3: Y = 4
PRINT "Distance: "; FND(0)
REM Output: Distance: 5
ENDSTART:
REM Random number in range
DEF FNR(N) = INT(RND(1) * N + 1)
FOR I = 1 TO 5
PRINT "Random 1-10: "; FNR(10)
NEXT I
ENDSTART:
REM Temperature conversion
DEF FNC(F) = (F - 32) * 5 / 9
DEF FNF(C) = C * 9 / 5 + 32
INPUT "Enter Fahrenheit: ", TEMP
PRINT TEMP; "F = "; FNC(TEMP); "C"
ENDKey Points:
- Function names must start with
FNfollowed by a letter (e.g.,FNA,FNB,FND) - Functions can have one parameter
- The function body must be a single expression
- User-defined functions can reference global variables
- Call functions using
FNname(argument)
10 REM This is a full-line comment
20 ' Apostrophe also starts a comment
30 X = 10 ' Inline comment at end of statement
40 PRINT "Hello" ' Comments work after any statementThe apostrophe (') can be used anywhere on a line to start a comment. Everything from the ' to the end of the line is ignored. This is useful for adding inline comments after code.
100 END ' Terminates program execution10 CLS ' Clears the screen| Function | Description | Example |
|---|---|---|
ABS(x) |
Absolute value | ABS(-5) → 5 |
INT(x) |
Integer part (floor) | INT(3.7) → 3 |
SGN(x) |
Sign (-1, 0, or 1) | SGN(-5) → -1 |
SQRT(x) |
Square root | SQRT(16) → 4 |
SQR(x) |
Square root (alias for SQRT) | SQR(16) → 4 |
SIN(x) |
Sine (radians) | SIN(3.14159/2) → 1 |
COS(x) |
Cosine (radians) | COS(0) → 1 |
TAN(x) |
Tangent (radians) | TAN(0) → 0 |
ATAN(x) |
Arctangent (radians) | ATAN(1) → 0.785... |
ASIN(x) |
Arcsine (radians), x must be -1 to 1 | ASIN(1) → 1.5707... |
ACOS(x) |
Arccosine (radians), x must be -1 to 1 | ACOS(0) → 1.5707... |
LOG(x) |
Natural logarithm | LOG(2.718) → 1 |
EXP(x) |
e raised to power | EXP(1) → 2.718... |
RND(x) |
Random nubmer 0-1 | RND(1) → 0.xxxxx |
| Function | Description | Example |
|---|---|---|
PI() |
Returns the value of π | PI() → 3.14159... |
RADIANS(deg) |
Convert degrees to radians | RADIANS(180) → 3.14159... |
DEGREES(rad) |
Convert radians to degrees | DEGREES(PI()) → 180 |
Example:
10 REM Trigonometry with degree/radian conversion
20 ANGLE = 45
30 RAD = RADIANS(ANGLE)
40 PRINT "Sin(45 degrees) = "; SIN(RAD)
50 PRINT "Asin result in degrees: "; DEGREES(ASIN(0.707))
60 END| Function | Description | Example |
|---|---|---|
LEN(s$) |
String length | LEN("Hello") → 5 |
LEFT$(s$,n) |
Left n characters | LEFT$("Hello",2) → "He" |
RIGHT$(s$,n) |
Right n characters | RIGHT$("Hello",2) → "lo" |
MID$(s$,p,n) |
Substring | MID$("Hello",2,3) → "ell" |
CHR$(n) |
Character from ASCII | CHR$(65) → "A" |
BOXCHAR$(n) |
Box-drawing character (1-6) | BOXCHAR$(1) → "┌" |
ASC(s$) |
ASCII from character | ASC("A") → 65 |
STR$(n) |
Number to string | STR$(42) → "42" |
VAL(s$) |
String to number | VAL("42") → 42 |
SPACE$(n) |
n spaces | SPACE$(5) → " " |
UCASE$(s$) |
Uppercase | UCASE$("hi") → "HI" |
LCASE$(s$) |
Lowercase | LCASE$("HI") → "hi" |
TRIM$(s$) |
Remove leading/trailing whitespace | TRIM$(" hi ") → "hi" |
LTRIM$(s$) |
Remove leading whitespace | LTRIM$(" hi") → "hi" |
RTRIM$(s$) |
Remove trailing whitespace | RTRIM$("hi ") → "hi" |
INSTR(s$,find$) |
Find position of substring (0 if not found) | INSTR("hello","ll") → 3 |
REPLACE$(s$,old$,new$) |
Replace all occurrences | REPLACE$("hello","l","L") → "heLLo" |
Returns box-drawing characters, useful for creating frames and boxes. On CP310 capable terminals, these display as graphical line characters. On CP037 terminals, use traditional mainframe boxdrawing characters (+, -, |).
| n | Character | Description |
|---|---|---|
| 1 | ┌ | Top-left corner |
| 2 | ┐ | Top-right corner |
| 3 | └ | Bottom-left corner |
| 4 | ┘ | Bottom-right corner |
| 5 | ─ | Horizontal line |
| 6 | │ | Vertical line |
10 REM Draw a simple box
20 PRINT BOXCHAR$(1) + BOXCHAR$(5) + BOXCHAR$(5) + BOXCHAR$(2)
30 PRINT BOXCHAR$(6) + " " + BOXCHAR$(6)
40 PRINT BOXCHAR$(3) + BOXCHAR$(5) + BOXCHAR$(5) + BOXCHAR$(4)Tip: Use $TermInfo to check if teh terminal supports CP310, and use ASCII characters (+, -, |) as fallback for CP037 terminals. See _terminfo.bas for a complete example.
Returns graphic characters from Code Page 310. Use with CP310-capable terminals for enhanced graphics.
| Range | Characters | Description |
|---|---|---|
| 1-6 | ┌ ┐ └ ┘ ─ │ | Single-line box (same as BOXCHAR$) |
| 7-12 | ╔ ╗ ╚ ╝ ═ ║ | Double-line box |
| 13-16 | ├ ┤ ┬ ┴ | T-junctions |
| 17-20 | ┼ ╬ ╠ ╣ | Cross junctions |
| 21-28 | █ ▀ ▄ ▌ ▐ ░ ▒ ▓ | Blocks & shades |
| 29-32 | ← → ↑ ↓ | Arrows |
| 33-36 | ■ □ ● ○ | Geometric shapes |
| 37-40 | ▲ ▼ ◄ ► | Triangle arrows |
| 41-44 | ╭ ╮ ╰ ╯ | Rounded corners |
| 45-50 | · • ╳ ╱ ╲ ∙ | Dots and diagonals |
10 REM Draw a double-line box with CP310$
20 DIM T{} : T{} = $TermInfo
30 IF T{"codepage"} <> "310" THEN PRINT "Need CP310 terminal" : END
40 PRINT CP310$(7) + CP310$(11) + CP310$(11) + CP310$(11) + CP310$(8)
50 PRINT CP310$(12) + " Hi " + CP310$(12)
60 PRINT CP310$(9) + CP310$(11) + CP310$(11) + CP310$(11) + CP310$(10)
70 PRINT
80 PRINT "Blocks: "; CP310$(21); CP310$(22); CP310$(23); CP310$(24); CP310$(25)
90 PRINT "Arrows: "; CP310$(29); CP310$(30); CP310$(31); CP310$(32)| Function | Description | Example |
|---|---|---|
TIME$() |
Current time (HH:MM:SS) | TIME$() → "14:30:45" |
DATE$() |
Current date (YYYY-MM-DD) | DATE$() → "2025-12-16" |
TIMER() |
Seconds since midnight (with millisecond precision) | TIMER() → 52245.123 |
HOUR() |
Current hour (0-23) | HOUR() → 14 |
MINUTE() |
Current minute (0-59) | MINUTE() → 30 |
SECOND() |
Current second (0-59) | SECOND() → 45 |
YEAR() |
Current year | YEAR() → 2025 |
MONTH() |
Current month (1-12) | MONTH() → 12 |
DAY() |
Day of month (1-31) | DAY() → 16 |
SLEEP(n) |
Pause execution for n seconds | SLEEP(1.5) pauses 1.5 sec |
The SLEEP(n) function pauses program execution for the specified number of seconds. Any call of SLEEP with more than 0.25 seconds will reward the program with more allowed iterations and wall clock time before the program is halted for excessive computation or wall clock. SLEEP spares the CPU as it is a non-busy wait function.
- Range: 0.1 to 255 seconds
- Fractions: Supports decimal values (e.g.,
SLEEP(0.5)for half a second) - CPU-friendly: Does not consume CPU cylces during the wait
- Returns: 0 (can be ignored)
Example (label-based):
START:
REM Countdown Timer
FOR I = 10 TO 0 STEP -1
PRINT I
X = SLEEP(1)
NEXT I
PRINT "BLAST OFF!"
ENDThe TAB(n) function is used in PRINT statements to move to a specific column position. It calculates how many spaces are needed to reach column n based on what has already been printed on the current line.
- Usage:
PRINT "text"; TAB(n); "more text" - Range: 1-255 (column 1 is the leftmost position)
- Behavior: Adds spaces to reach column n; if already past column n, no spaces are added
Examples (label-based):
START:
REM Formatted output with TAB
PRINT "Name"; TAB(15); "Age"; TAB(25); "City"
PRINT "Alice"; TAB(15); "25"; TAB(25); "Boston"
PRINT "Bob"; TAB(15); "30"; TAB(25); "Chicago"
ENDOutput:
Name Age City
Alice 25 Boston
Bob 30 Chicago
START:
REM Centering text
FOR I = 1 TO 5
PRINT TAB(I * 5); "*"
NEXT I
ENDNote: TAB returns spaces to reach the specified column position. It's most useful for creating aligned tabular output.
The EVAL(expr$) function evaluates a string as a BASIC expression at runtime and returns the results.
- Input: A string containing a valid BASIC expression
- Returns: The evaluated result (number or string)
- Variables: Can reference current program variables
Examples (label-based):
START:
REM Simple calculator
INPUT "Enter expression: ", E$
PRINT "Result: "; EVAL(E$)
ENDSTART:
REM Using variables in EVAL
A = 10
B = 5
PRINT EVAL("A + B") ' Prints 15
PRINT EVAL("A * B + 2") ' Prints 52
ENDSTART:
REM Dynamic math
FORMULA$ = "SIN(X) * 2"
FOR X = 0 TO 3
PRINT "X="; X; " Result="; EVAL(FORMULA$)
NEXT X
ENDSTART:
REM String functions in EVAL
NAME$ = "HELLO WORLD"
PRINT EVAL("LEFT$(NAME$, 5)") ' Prints HELLO
ENDCall other BASIC programs and share data between them using COMMON and CHAIN.
Declare variables that persist across CHAIN calls:
COMMON var1, var2, var3$Variables declared with COMMON retain their values when you CHAIN to another program. Variables not declared as COMMON are cleared.
Load and run another BASIC program:
CHAIN "programname"When the chained program ends (via END), control returns to the calling program at the line after CHAIN. COMMON variables are preserved in both directions.
Example - Main Program:
10 REM Main program
20 NAME$ = "John"
30 COUNT = 42
40 COMMON NAME$, COUNT, RESULT
50 CHAIN "helper"
60 PRINT "Back from helper"
70 PRINT "Result: "; RESULT
80 ENDExample - Helper Program (helper.bas):
10 REM Helper program
20 COMMON NAME$, COUNT, RESULT
30 PRINT "Hello, "; NAME$
40 RESULT = COUNT * 2
50 ENDNotes:
- Programs must exist in your directory or community folder
- COMMON declarations must appear before CHAIN is executed
Read and write data files from your BASIC programs.
Open a file for reading, writing, or appending:
OPEN "filename.dat" FOR INPUT AS #1
OPEN "filename.dat" FOR OUTPUT AS #2
OPEN "filename.dat" FOR APPEND AS #3Modes:
INPUT- Read from existing fileOUTPUT- Create new file (overwrites if exists)APPEND- Add to end of existing file (creates if not exists)
File Numbers: Use #1 through #4 (max 4 files open at once)
Write to an open file:
PRINT #1, "Hello World"
PRINT #1, "Score: "; SCORE
PRINT #2, A$; ","; B$Read a line from an open file:
INPUT #1, LINE$
INPUT #1, DATA$Each INPUT reads one line from the file.
Close an open file:
CLOSE #1 ' Close file #1
CLOSE ' Close all open filesImportant: Always CLOSE files when done. Files are also automatically closed when program ends.
Check if at end of file:
IF EOF(1) THEN PRINT "End of file reached"
WHILE NOT EOF(1)
INPUT #1, LINE$
PRINT LINE$
WENDReturns 1 if at end of file, 0 otherwise.
Writing a data file (label-based):
START:
REM Write high scores to file
OPEN "scores.dat" FOR OUTPUT AS #1
PRINT #1, "Player1,1500"
PRINT #1, "Player2,1200"
PRINT #1, "Player3,900"
CLOSE #1
PRINT "Scores saved!"
ENDReading a data file (label-based):
START:
REM Read and display file contents
OPEN "scores.dat" FOR INPUT AS #1
PRINT "=== HIGH SCORES ==="
WHILE NOT EOF(1)
INPUT #1, LINE$
PRINT LINE$
WEND
CLOSE #1
ENDAppending to a file (label-based):
START:
REM Add new score
INPUT "Player name: ", NAME$
INPUT "Score: ", SCORE
OPEN "scores.dat" FOR APPEND AS #1
PRINT #1, NAME$; ","; SCORE
CLOSE #1
PRINT "Score added!"
ENDLimits and Security:
- File names must end in
.dator in '.idx' - Files stored in your BASIC directory only
- No path separators allowed in filenames
Error Messages:
| Error | Description |
|---|---|
?FILE NOT FOUND |
File doesn't exist (INPUT mode) |
?FILE ALREADY OPEN |
File handle already in use |
?BAD FILE NUMBER |
Invalid handle (not 1-4) or not open |
?FILE SIZE LIMIT EXCEEDED |
Write would exceed 256KB |
?ILLEGAL FILE NAME |
Invalid characters or missing .dat |
?INPUT PAST END |
Attempted read after EOF |
Version 2.9.0 introduces indexed file support using associative arrays as records. This provides random access by key or record number, similar to VSAM/ISAM on mainframes.
Use the INDEXED mode with a key field:
DIM C{}
OPEN "contacts.dat" FOR INDEXED AS #1 KEY = "id"The key field specifies which field in your associative array serves as the primary key.
Store an associative array as a record:
DIM C{}
OPEN "contacts.dat" FOR INDEXED AS #1 KEY = "id"
C{"id"} = "001"
C{"name"} = "John Smith"
C{"city"} = "New York"
PUT #1, C{}
CLOSE #1If a record with the same key exists, it is updated. Otherwise, a new record is added.
Retrieve records by key, record number, or sequentially:
By Key:
DIM C{}
OPEN "contacts.dat" FOR INDEXED AS #1 KEY = "id"
GET #1, C{}, KEY = "001"
IF FOUND(1) THEN
PRINT "Name: "; C{"name"}
ELSE
PRINT "Not found"
ENDIF
CLOSE #1By Record Number:
GET #1, C{}, REC = 1Sequential Access:
RESET #1
WHILE NOT EOF(1)
GET #1, C{}, NEXT
IF FOUND(1) THEN
PRINT C{"id"}; " - "; C{"name"}
ENDIF
WENDDelete by key or record number:
DELETE #1, KEY = "001"
DELETE #1, REC = 2| Function | Description |
|---|---|
FOUND(n) |
Returns 1 if last GET found a record |
DELETED(n) |
Returns 1 if current record is deleted |
EOF(n) |
Returns 1 if at end of file |
RESET #n |
Rewind file for sequential reading |
MAIN:
DIM CONTACT{}
OPEN "rolodex.dat" FOR INDEXED AS #1 KEY = "id"
GOSUB ADDCONTACT
GOSUB LISTALL
CLOSE #1
END
ADDCONTACT:
CONTACT{"id"} = "C001"
CONTACT{"name"} = "Alice"
CONTACT{"phone"} = "555-1234"
PUT #1, CONTACT{}
RETURN
LISTALL:
RESET #1
WHILE NOT EOF(1)
GET #1, CONTACT{}, NEXT
IF FOUND(1) THEN
PRINT CONTACT{"name"}; ": "; CONTACT{"phone"}
ENDIF
WEND
RETURN| Error | Description |
|---|---|
?FILE NOT OPENED FOR INDEXED |
Using PUT/GET on non-indexed file |
?ARRAY NOT DEFINED |
Associative array not declared with DIM |
?KEY FIELD NOT SET |
PUT without setting the key field |
Access live BBS data direcly from BASIC!
$ChatMessage(n) returns an associative array with structured chat data from the global (public) chat room.
10 DIM C{} ' Declare associative array
20 C{} = $ChatMessage(0) ' Get most recent message
30 PRINT C{"username"}; ": "; C{"message"}
40 PRINT "Time: "; C{"datetime"}Available Keys:
| Key | Description |
|---|---|
datetime |
ISO 8601 format: YYYY-MM-DDTHH:MM:SS |
username |
Who posted the message |
message |
Message content |
Index:
n=0: Most recent messagen=1orn=-1: Second most recent- Empty values returned if no messages
Note: Only returns messages from the public global chat room, not private rooms.
$Mail(n) returns an associative array with structured mail data:
10 DIM MAIL{} ' Declare associative array
20 MAIL{} = $Mail(0) ' Get most recent mail
30 PRINT MAIL{"from"} ' Sender name
40 PRINT MAIL{"datetime"} ' ISO 8601: 2025-12-17T14:30:45
50 PRINT MAIL{"body"} ' Full message bodyAvailable Keys:
| Key | Description |
|---|---|
datetime |
ISO 8601 format: YYYY-MM-DDTHH:MM:SS |
from |
Sender username |
body |
Complete message content |
read |
"1" if read, "0" if unread |
replied |
"1" if replied, "0" if not |
id |
Message ID number |
Index:
n=0: Most recent messagen=-1orn=1: Second most recent- Empty values returned if no mail exists
$UserInfo returns an associative array with your user profile data. Only non-sensitive fields are exposed.
10 DIM U{} ' Declare associative array
20 U{} = $UserInfo ' Get user info
30 PRINT "Hello, "; U{"username"}
40 IF U{"country"} <> "" THEN PRINT "Country: "; U{"country"}Available Keys:
| Key | Description |
|---|---|
username |
Your username |
country |
Your country (may be empty) |
Note: Admin-only fields like email, IP address, role, and ban status are intentionally not exposed to any user, including admins and moderators.
$TermInfo returns an associative array with information about your current terminal session.
10 DIM T{} ' Declare associative array
20 T{} = $TermInfo ' Get terminal info
30 PRINT "Terminal: "; T{"model"}
40 PRINT "Codepage: "; T{"codepage"}
50 IF T{"codepage"} = "310" THEN PRINT "Graphics characters available!"Available Keys:
| Key | Description |
|---|---|
model |
Terminal model: "Mod2" (24x80), "Mod3" (32x80), or "Mod4" (43x80) |
codepage |
Terminal codepage: "310" (with graphics) or "037" (standard EBCDIC) |
$Topic(n) returns an associative array with topic metadata. Only returns topics the user has permission to access (respects admin-only, moderator-only, and banned user restrictions).
10 DIM T{} ' Declare associative array
20 T{} = $Topic(0) ' Get most recent accessible topic
30 PRINT T{"title"} ' Topic title
40 PRINT T{"author"} ' Author username
50 PRINT T{"conference"} ' Conference nameAvailable Keys:
| Key | Description |
|---|---|
id |
Topic ID (use with $Post) |
title |
Topic title |
author |
Username who created it |
conference |
Conference name |
datetime |
ISO 8601: YYYY-MM-DDTHH:MM:SS |
posts |
Number of posts/replies |
views |
View count |
likes |
Total likes |
Index:
n=0: Most recent topicn=1: Second most recent- Empty values returned if no topics or access denied
$Post(topic_id, n) returns an associative array with post data from a specific topic. Verifies user has permission to access the topic's conference.
10 DIM T{}
20 T{} = $Topic(0) ' Get topic
30 TOPIC_ID = VAL(T{"id"}) ' Get topic ID
40 DIM P{}
50 P{} = $Post(TOPIC_ID, 0) ' Get first post
60 PRINT P{"author"}; ": "; P{"body"}Available Keys:
| Key | Description |
|---|---|
id |
Post ID |
author |
Username who wrote it |
body |
Post content |
datetime |
ISO 8601: YYYY-MM-DDTHH:MM:SS |
likes |
Like count |
dislikes |
Dislike count |
Arguments:
topic_id: The topic ID (fromT{"id"}after$Topic())n=0: First post (oldest),n=1: Second post, etc.- Empty values returned if topic not found or access denied
The BASIC/3270BBS compiler automatically applies safe optimizations to improve runtime performance. These optimizations are performed at compile time when you LOAD or enter a program, and are visible in the CHECK command's OPTIMIZER REPORT section.
When the compiler detects arithmetic operations with literal (constant) numbers, it evaluates them at compile time instead of at runtime. This eliminates redundant calculations during program execution.
Example - Before optimization:
10 X = 2 + 3 * 4
20 AREA = 3.14159 * 10 * 10
30 TIMEOUT = 60 * 60 * 24After optimization (internally):
10 X = 14
20 AREA = 314.159
30 TIMEOUT = 86400Supported operations: +, -, *, /, ^ (power), MOD
Note: The compiler will NOT optimize division or MOD by zero - these remain unevaluated to produce proper runtime errors.
For certain built-in functions called with constant (literal) arguments, the compiler evaluates the function at compile time.
Example - Before optimization:
10 SPACE_CODE = ASC(" ")
20 MSG_LEN = LEN("Hello, World!")
30 CHAR_A = CHR$(65)
40 VALUE = VAL("42.5")
50 TEXT = STR$(100)After optimization (internally):
10 SPACE_CODE = 32
20 MSG_LEN = 13
30 CHAR_A = "A"
40 VALUE = 42.5
50 TEXT = "100"Precomputed functions:
| Function | Description | Example | Result |
|---|---|---|---|
LEN() |
String length | LEN("HELLO") |
5 |
ASC() |
Character to ASCII | ASC("A") |
65 |
CHR$() |
ASCII to character | CHR$(65) |
"A" |
VAL() |
String to number | VAL("123") |
123 |
STR$() |
Number to string | STR$(42) |
"42" |
Use the CHECK command to see what optimizations were applied to your program. The listing includes an OPTIMIZER REPORT section:
OPTIMIZER REPORT
LINE TYPE ORIGINAL OPTIMIZED
---- ---- -------- ---------
10 CONSTANT_FOLD 2 + 3 * 4 14
20 CONSTANT_FOLD 3.14159 * 10 * 10 314.159
30 FUNC_PRECOMPUTE LEN("Hello, World!") 13
40 FUNC_PRECOMPUTE ASC("A") 65
TOTAL OPTIMIZATIONS: 4
The optimizer only applies safe transformations that do not change program behavior:
- Only constant expressions are folded (variables are never evaluated at compile time)
- Division/MOD by zero is not optimized (proper runtime error handling preserved)
- Functions with side effects (like
RND,TIMER(),INKEY$) are never precomputed - String concatenation with variables is not optimized
This program draws a sine curve usign asterisks:
10 REM Sine Wave Graph
20 FOR I = 0 TO 20
30 X = I * 0.3
40 Y = SIN(X)
50 S = INT((Y + 1) * 20)
60 PRINT SPACE$(S); "*"
70 NEXT I
80 ENDOutput:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
This program retrieves and displays the three most recent chat messages from the BBS:
START:
REM Display Last 3 Chat Messages
DIM C{}
PRINT "=============================="
PRINT " RECENT CHAT MESSAGES"
PRINT "=============================="
PRINT
FOR I = 0 TO 2
C{} = $ChatMessage(I)
IF C{"message"} = "" THEN GOTO Done
PRINT C{"datetime"}; " "; C{"username"}; ": "; C{"message"}
NEXT I
Done:
PRINT
PRINT "=============================="
ENDSTART:
REM User Greeting
DIM U{}
U{} = $UserInfo
PRINT "Welcome, "; U{"username"}; "!"
IF U{"country"} <> "" THEN PRINT "Connecting from: "; U{"country"}
ENDSTART:
REM Personal Dashboard
DIM U{} : DIM M{} : DIM C{} : DIM T{}
U{} = $UserInfo
PRINT "==============================="
PRINT " WELCOME, "; U{"username"}
PRINT "==============================="
PRINT
PRINT "Your latest mail:"
M{} = $Mail(0)
IF M{"datetime"} <> "" THEN PRINT " From: "; M{"from"}; " - "; LEFT$(M{"body"}, 40)
IF M{"datetime"} = "" THEN PRINT " No mail"
PRINT
PRINT "Latest chat:"
C{} = $ChatMessage(0)
IF C{"message"} <> "" THEN PRINT " "; C{"username"}; ": "; C{"message"}
IF C{"message"} = "" THEN PRINT " No messages"
PRINT
PRINT "Latest topic:"
T{} = $Topic(0)
IF T{"title"} <> "" THEN PRINT " "; T{"title"}; " by "; T{"author"}
IF T{"title"} = "" THEN PRINT " No topics"
ENDThis program reads and displays your most recent email with full details. Demonstrates both single-line and multi-line IF syntax:
START:
REM Mail Reader Example
DIM MAIL{}
MAIL{} = $Mail(0)
IF MAIL{"datetime"} = "" THEN GOTO NoMail
PRINT "From: "; MAIL{"from"}
PRINT "Date: "; MAIL{"datetime"}
PRINT "Status: ";
IF MAIL{"read"} = "1" THEN GOSUB ShowRead ELSE PRINT "Unread" COLOR YELLOW
PRINT "---Message---"
PRINT MAIL{"body"}
END
NoMail:
PRINT "No mail"
END
ShowRead:
PRINT "Read"
IF MAIL{"replied"} = "1" THEN PRINT "(Replied)"
RETURNThis program reads a topic and displays all its posts:
START:
REM Topic and Posts Reader
DIM T{}
DIM P{}
REM Get the most recent topic
T{} = $Topic(0)
IF T{"title"} = "" THEN PRINT "No topics available": END
PRINT "================================"
PRINT T{"title"}
PRINT "by "; T{"author"}; " in "; T{"conference"}
PRINT "Posted: "; T{"datetime"}
PRINT "================================"
PRINT
REM Get the topic ID for fetching posts
TOPIC_ID = VAL(T{"id"})
NUM_POSTS = VAL(T{"posts"})
REM Display all posts in this topic
FOR I = 0 TO NUM_POSTS - 1
P{} = $Post(TOPIC_ID, I)
IF P{"body"} = "" THEN GOTO SkipPost
PRINT "--- "; P{"author"}; " ("; P{"datetime"}; ") ---"
PRINT P{"body"}
PRINT "Likes: "; P{"likes"}; " Dislikes: "; P{"dislikes"}
PRINT
SkipPost:
NEXT I
ENDThis program displays the current date and time using all time functions:
START:
REM Digital Clock Display
PRINT "================================"
PRINT " CURRENT DATE AND TIME"
PRINT "================================"
PRINT
PRINT " Date: "; DATE$()
PRINT " Time: "; TIME$()
PRINT
PRINT " Year: "; YEAR()
PRINT " Month: "; MONTH()
PRINT " Day: "; DAY()
PRINT " Hour: "; HOUR()
PRINT " Minute: "; MINUTE()
PRINT " Second: "; SECOND()
PRINT
PRINT " Seconds since midnight: "; TIMER()
ENDThis program plots an elliptical orbit around a central body using ASCII graphics. Fits within the 24x80 Model 2 terminal display:
10 REM Orbital Mechanics Plotter
20 REM Fits 24x80 Model 2 Terminal
30 DIM SCR$(18)
40 W = 70: H = 16
50 CX = 35: CY = 8
60 A = 28: B = 7
70 E = 0.6
80 REM Initialize screen buffer
90 FOR Y = 0 TO H-1
100 SCR$(Y) = SPACE$(W)
110 NEXT Y
120 REM Plot elliptical orbit path
130 FOR T = 0 TO 62
140 AN = T * 0.1
150 R = (A * (1 - E*E)) / (1 + E * COS(AN))
160 PX = INT(CX + R * COS(AN) * 0.5)
170 PY = INT(CY + R * SIN(AN) * 0.25)
180 IF PX >= 0 AND PX < W AND PY >= 0 AND PY < H THEN GOSUB 400
190 NEXT T
200 REM Place Sun at focus
210 PX = CX - INT(A * E * 0.5): PY = CY
220 CH$ = "@": GOSUB 400
230 REM Place satellite
240 AN = 0.8: R = (A * (1 - E*E)) / (1 + E * COS(AN))
250 PX = INT(CX + R * COS(AN) * 0.5)
260 PY = INT(CY + R * SIN(AN) * 0.25)
270 CH$ = "*": GOSUB 400
280 REM Print the display
290 PRINT "ORBITAL MECHANICS - ELLIPTICAL ORBIT"
300 PRINT "Eccentricity: "; E; " Semi-major: "; A
310 FOR Y = 0 TO H-1
320 PRINT SCR$(Y)
330 NEXT Y
340 PRINT "@ = Sun (focus) * = Satellite . = Orbit path"
350 END
400 REM Subroutine: Plot character at PX,PY
410 IF CH$ = "" THEN CH$ = "."
420 L$ = SCR$(PY)
430 IF PX = 0 THEN SCR$(PY) = CH$ + MID$(L$, 2)
440 IF PX > 0 AND PX < W-1 THEN SCR$(PY) = LEFT$(L$, PX) + CH$ + MID$(L$, PX+2)
450 IF PX = W-1 THEN SCR$(PY) = LEFT$(L$, PX) + CH$
460 CH$ = "."
470 RETURNOutput:
ORBITAL MECHANICS - ELLIPTICAL ORBIT
Eccentricity: 0.6 Semi-major: 28
...........
... ....
.. ...
. ..
. .
. .
. @ * .
. .
. .
. ..
.. ...
... ....
...........
@ = Sun (focus) * = Satellite . = Orbit path
This program demonstrates associative arrays to create a simple phone book:
START:
REM Simple Phone Book using Associative Arrays
DIM PHONE${}
PRINT "=== PHONE BOOK ==="
PRINT
REM Add some entries
PHONE${"Alice"} = "555-1234"
PHONE${"Bob"} = "555-5678"
PHONE${"Carol"} = "555-9012"
PHONE${"David"} = "555-3456"
PRINT "Stored 4 contacts."
PRINT
Lookup:
INPUT "Enter name to look up: ", NAME$
RESULT$ = PHONE${NAME$}
IF RESULT$ = "" THEN PRINT "Not found!" COLOR RED: GOTO AskAgain
PRINT NAME$; ": "; RESULT$ COLOR GREEN
AskAgain:
PRINT
INPUT "Look up another? (Y/N): ", A$
IF UCASE$(A$) = "Y" THEN GOTO Lookup
PRINT "Goodbye!"
END| Key | Action |
|---|---|
| Enter | Execute comand / Submit input |
| Clear | Clear screen, show new READY prompt |
| PA1 / PA2 | Break/stop running program |
| PF11 / PF12 | Step through command history |
- Line Numbers: Use increments of 10 (10, 20, 30...) so you can insert lines latter
- RENUM: If you run out of space beetween lines, use
RENUMto renumber - Save Often: Use
SAVE "myprogram"to save your work - Debug: Use
PRINTstatments to check variable values - Variables: String variables must end wiht
$(e.g.,NAME$)
COMMANDS: RUN LIST NEW SAVE LOAD RENAME EDIT BROWSE ERASE FILES FLIST RENUM DELETE HELP VARS BYE
FILES: FILES [pattern] [/W] [/C] [/U user] FLIST [pattern] [/W]
Wildcards: * (any chars), ? (single char) e.g. FILES *.bas
SYNTAX: CHECK - Syntax check, generate name.list (or UNNAMED.list)
VIEW name.list - View listing without clearing program
EMAIL name.list - Email listing as PDF to your email
STATEMENTS: PRINT INPUT LET IF/THEN/ELSE/ELSEIF/END IF GOTO GOSUB/RETURN
FOR/NEXT WHILE/WEND SELECT CASE/END SELECT DIM REM ' END CLS
COMMON CHAIN OPEN CLOSE SLEEP ON...GOTO ON...GOSUB DEF FN
COMMENTS: REM comment text ' Full line comment
code ' comment ' Inline comment after code
PRINT COLOR: PRINT "text" COLOR colorname [BLINK|REVERSEVIDEO]
Colors: WHITE RED YELLOW PINK GREEN BLUE TURQUOISE
COMPUTED: ON expr GOTO line1,line2,... ' Jump based on expression value
ON expr GOSUB line1,line2,... ' Call subroutine based on expression
DEF FNx(param) = expression ' Define user function
MATH: ABS INT SGN SQRT SQR SIN COS TAN ATAN ASIN ACOS LOG EXP RND
PI() RADIANS(deg) DEGREES(rad)
STRING: LEN LEFT$ RIGHT$ MID$ CHR$ ASC STR$ VAL SPACE$ UCASE$ LCASE$
TRIM$ LTRIM$ RTRIM$ INSTR REPLACE$
FILE I/O: OPEN "file.dat" FOR INPUT|OUTPUT|APPEND AS #n
PRINT #n, expression INPUT #n, variable CLOSE #n
EOF(n) - Returns 1 if at end of file
INDEXED: OPEN "file.dat" FOR INDEXED AS #n KEY = "field"
PUT #n, array{} GET #n, array{}, KEY = expr
GET #n, array{}, REC = n GET #n, array{}, NEXT
DELETE #n, KEY = expr DELETE #n, REC = n
RESET #n FOUND(n) DELETED(n)
CHAINING: COMMON var1, var2 ' Declare shared variables
CHAIN "program" ' Call another program
GRAPHICS: BOXCHAR$(1-6) CP310$(1-50) - Box drawing and grahpic characters
TIME: TIME$() DATE$() TIMER() HOUR() MINUTE() SECOND()
YEAR() MONTH() DAY() SLEEP(n)
OUTPUT: TAB(n) - Move to colun n in PRINT statements
UTILITY: EVAL(expr$) - Evaluate string as expression at runtime
BBS DATA: $ChatMessage(n) $Mail(n) $UserInfo $TermInfo $Topic(n) $Post(topic_id,n)
This section documents the built-in limits of the BASIC interpreter.
| Limit | Value | Description |
|---|---|---|
| Line length | 255 characters | Maximum characters per source line |
| Program size | 256 KB | Maximum file size for BASIC programs |
| Limit | Value | Description |
|---|---|---|
| Dimension size | 10,000 | Maximum size per array dimension |
| Total elements | 100,000,000 | Maximum for 2D array (10000 x 10000) |
| Associative arrays | Unlimited | Limited only by available memory |
| Limit | Value | Description |
|---|---|---|
| Iterations | 55,000,000 | Maximum loop iterations before timeout |
| Execution time | 15 seconds | Maximum runtime (excluding SLEEP) |
| Sleep credit | 15% | Percentage of used resources credited back when SLEEP is called |
Programs that call SLEEP with duration >= 0.1 seconds receive credit that extends both iteration and time limits.
| Limit | Value | Description |
|---|---|---|
| Open files | 4 | Maximum concurrent open files (#1 to #4) |
| File size | 256 KB | Maximum size for data files |
| Output buffer | 1,000 lines | Maximum lines in screen output buffer |
| Limit | Value | Description |
|---|---|---|
| Minimum | 0.1 seconds | Shortest allowed sleep duration |
| Maximum | 255 seconds | Longest allowed sleep duration |
The following control structures have no explicit depth limit and are limited only by available memory:
- GOSUB/RETURN - Subroutine call stack
- FOR/NEXT - Loop nesting
- WHILE/WEND - Loop nesting
- IF/END IF - Conditional block nesting
- SELECT CASE/END SELECT - Case block nesting
- CHAIN - Program chaining stack
- Must start with a letter (A-Z)
- Can contain letters and digits
- String variables end with
$(e.g.,NAME$) - Case insensitive (
countandCOUNTare the same variable) - Reserved keywords cannot be used as variable names
- Strings are dynamically sized with no fixed maximum length
- String functions like
SPACE$()andSTRING$()cap repetition at 255 characters
New File Commands:
-
RENAME "old.bas" "new.bas": Rename a .bas file. Both filenames must include the .bas extension to avoid conflicts with .list, .dat, and .idx files.
-
ERASE with wildcards: ERASE now supports MS-DOS style wildcards for bulk deletion:
?= single character placeholder*= wildcard (zero or more characters)- Works with .bas, .list, .dat, .idx extensions
- Example:
ERASE pi*.*deletes all files starting with "pi" and any extension - Example:
ERASE a???.basdeletes 4-character .bas files (a001.bas, abcd.bas, etc.)
New Feature: Indexed Files (ISAM)
- OPEN FOR INDEXED: Open data files for random access by key
- PUT #n, array{}: Write associative array as a record
- GET #n, array{}, KEY=expr: Read record by key value
- GET #n, array{}, REC=n: Read record by number
- GET #n, array{}, NEXT: Sequential read
- DELETE #n, KEY=expr: Delete record by key
- DELETE #n, REC=n: Delete record by number
- RESET #n: Rewind file for sequential read
- FOUND(n): Check if last GET found a record
- DELETED(n): Check if current record is deleted
This feature enables database-like operations using associative arrays as records, providing a familiar ISAM/VSAM experience.
Syntax Checker Fix:
- Fixed whole-array assignment syntax: The syntax checker now correctly handles whole-array assignment using empty braces (e.g.,
U{} = $UserInfo). Previously, this would incorrectly report "EXPECTED EXPRESSION" because the checker expected a key inside the braces.
Syntax Checker Improvements:
-
Fixed OPEN statement with variable filenames: The syntax checker now correctly handles OPEN statements where the filename is a variable (e.g.,
OPEN FILENAME$ FOR INPUT AS #1). Previously, this would incorrectly report "EXPECTED FOR AFTER FILENAME". -
Fixed associative array assignments: The syntax checker now properly validates associative array assignments using curly brace syntax (e.g.,
IDX{KEY$} = "value"). Previously, this would report "EXPECTED =". -
FN is no longer a reserved keyword: You can now use
FNas a variable name (though this is not recommended). This fixes the "UNKNOWN STATEMENT: FN" error when usingFNas a loop variable or in assignments likeFN = 1. TheDEF FNsyntax continues to work correctly.
Note for Programmers:
- While
FNcan now be used as a variable name, it's strongly recommended to avoid this practice as it may cause confusion with user-defined functions (DEF FN). - The recommended pattern for user-defined functions remains:
DEF FNX(param) = expression
TIMESHARING BASIC/3270BBS v2.9.2 - Happy coding! 🚀