DVX_GUI/docs/dvxbasic_language_reference.html
2026-04-06 22:25:06 -05:00

1973 lines
46 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DVX BASIC Language Reference</title>
<style>
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
max-width: 960px;
margin: 0 auto;
padding: 20px 30px;
background: #fdfdfd;
color: #222;
line-height: 1.55;
}
h1 {
border-bottom: 3px solid #336;
padding-bottom: 8px;
color: #224;
}
h2 {
border-bottom: 2px solid #99a;
padding-bottom: 4px;
margin-top: 40px;
color: #335;
}
h3 {
margin-top: 28px;
color: #446;
}
h4 {
margin-top: 20px;
margin-bottom: 4px;
color: #557;
}
pre {
background: #f0f0f4;
border: 1px solid #ccc;
border-left: 4px solid #669;
padding: 10px 14px;
overflow-x: auto;
font-size: 14px;
line-height: 1.4;
}
code {
background: #eef;
padding: 1px 5px;
border-radius: 3px;
font-size: 14px;
}
table {
border-collapse: collapse;
width: 100%;
margin: 10px 0 18px 0;
}
th, td {
border: 1px solid #bbb;
padding: 6px 10px;
text-align: left;
vertical-align: top;
}
th {
background: #e0e0ea;
color: #333;
}
tr:nth-child(even) {
background: #f5f5f9;
}
#toc {
background: #f0f0f6;
border: 1px solid #bbc;
padding: 14px 20px;
margin-bottom: 30px;
}
#toc ul {
margin: 0;
padding-left: 22px;
}
#toc li {
margin: 3px 0;
}
#toc a {
text-decoration: none;
color: #336;
}
#toc a:hover {
text-decoration: underline;
}
a {
color: #336;
}
.sig {
font-weight: bold;
color: #224;
}
.note {
background: #fffff0;
border-left: 4px solid #cc9;
padding: 8px 12px;
margin: 10px 0;
font-size: 14px;
}
</style>
</head>
<body>
<h1>DVX BASIC Language Reference</h1>
<p>Complete reference for the DVX BASIC language as implemented in the
DVX BASIC compiler and runtime. DVX BASIC is a QuickBASIC/Visual Basic
compatible dialect targeting the DVX GUI environment.</p>
<div id="toc">
<strong>Table of Contents</strong>
<ul>
<li><a href="#data-types">1. Data Types</a></li>
<li><a href="#operators">2. Operators</a></li>
<li><a href="#statements">3. Statements</a>
<ul>
<li><a href="#stmt-dim">DIM</a></li>
<li><a href="#stmt-redim">REDIM</a></li>
<li><a href="#stmt-const">CONST</a></li>
<li><a href="#stmt-type">TYPE...END TYPE</a></li>
<li><a href="#stmt-if">IF...THEN...ELSE...END IF</a></li>
<li><a href="#stmt-select">SELECT CASE</a></li>
<li><a href="#stmt-for">FOR...NEXT</a></li>
<li><a href="#stmt-do">DO...LOOP</a></li>
<li><a href="#stmt-while">WHILE...WEND</a></li>
<li><a href="#stmt-sub">SUB...END SUB</a></li>
<li><a href="#stmt-function">FUNCTION...END FUNCTION</a></li>
<li><a href="#stmt-def">DEF FN</a></li>
<li><a href="#stmt-exit">EXIT</a></li>
<li><a href="#stmt-call">CALL</a></li>
<li><a href="#stmt-goto">GOTO / GOSUB / RETURN</a></li>
<li><a href="#stmt-on">ON...GOTO / ON...GOSUB</a></li>
<li><a href="#stmt-print">PRINT</a></li>
<li><a href="#stmt-input">INPUT</a></li>
<li><a href="#stmt-data">DATA / READ / RESTORE</a></li>
<li><a href="#stmt-assign">Assignment</a></li>
<li><a href="#stmt-swap">SWAP</a></li>
<li><a href="#stmt-erase">ERASE</a></li>
<li><a href="#stmt-option">OPTION</a></li>
<li><a href="#stmt-deftype">DEFtype</a></li>
<li><a href="#stmt-static">STATIC</a></li>
<li><a href="#stmt-error">Error Handling</a></li>
<li><a href="#stmt-shell">SHELL</a></li>
<li><a href="#stmt-sleep">SLEEP</a></li>
<li><a href="#stmt-randomize">RANDOMIZE</a></li>
<li><a href="#stmt-end">END</a></li>
<li><a href="#stmt-declare">DECLARE</a></li>
<li><a href="#stmt-declarelib">DECLARE LIBRARY</a></li>
</ul>
</li>
<li><a href="#file-io">4. File I/O</a></li>
<li><a href="#builtin-functions">5. Built-in Functions</a>
<ul>
<li><a href="#func-string">String Functions</a></li>
<li><a href="#func-math">Math Functions</a></li>
<li><a href="#func-conversion">Conversion Functions</a></li>
<li><a href="#func-fileio">File I/O Functions</a></li>
<li><a href="#func-misc">Miscellaneous Functions</a></li>
</ul>
</li>
<li><a href="#form-controls">6. Form and Control Statements</a></li>
<li><a href="#sql-functions">7. SQL Functions</a></li>
<li><a href="#app-object">8. App Object</a></li>
<li><a href="#ini-functions">9. INI Functions</a></li>
<li><a href="#predefined-constants">10. Predefined Constants</a></li>
</ul>
</div>
<!-- ============================================================ -->
<h2 id="data-types">1. Data Types</h2>
<!-- ============================================================ -->
<p>DVX BASIC supports the following data types. Each type has a corresponding
type suffix character that can be appended to variable names.</p>
<table>
<tr>
<th>Type</th>
<th>Size</th>
<th>Suffix</th>
<th>Range / Description</th>
</tr>
<tr>
<td><code>Integer</code></td>
<td>2 bytes</td>
<td><code>%</code></td>
<td>-32768 to 32767</td>
</tr>
<tr>
<td><code>Long</code></td>
<td>4 bytes</td>
<td><code>&amp;</code></td>
<td>-2147483648 to 2147483647</td>
</tr>
<tr>
<td><code>Single</code></td>
<td>4 bytes</td>
<td><code>!</code></td>
<td>32-bit float, approximately 7 digits precision</td>
</tr>
<tr>
<td><code>Double</code></td>
<td>8 bytes</td>
<td><code>#</code></td>
<td>64-bit float, approximately 15 digits precision</td>
</tr>
<tr>
<td><code>String</code></td>
<td>variable</td>
<td><code>$</code></td>
<td>Variable-length, reference-counted, dynamic string</td>
</tr>
<tr>
<td><code>Boolean</code></td>
<td>2 bytes</td>
<td></td>
<td>True (-1) or False (0)</td>
</tr>
</table>
<h3>Internal Types (not directly declarable)</h3>
<table>
<tr>
<th>Internal Type</th>
<th>Description</th>
</tr>
<tr>
<td>Array</td>
<td>Reference-counted multi-dimensional array (up to 8 dimensions)</td>
</tr>
<tr>
<td>UDT</td>
<td>User-defined type instance (created with <code>TYPE...END TYPE</code>)</td>
</tr>
<tr>
<td>Object</td>
<td>Opaque host object (form reference, control reference)</td>
</tr>
<tr>
<td>Ref</td>
<td>ByRef pointer to a variable slot (used for ByRef parameters)</td>
</tr>
</table>
<h3>Type Suffixes</h3>
<p>Type suffixes can be appended to variable names to declare their type
implicitly:</p>
<pre>
count% = 42 ' Integer
total&amp; = 100000 ' Long
rate! = 3.14 ' Single
pi# = 3.14159265 ' Double
name$ = "Hello" ' String
</pre>
<h3>Numeric Literals</h3>
<table>
<tr><th>Form</th><th>Example</th><th>Description</th></tr>
<tr><td>Decimal integer</td><td><code>42</code></td><td>Values -32768..32767 are Integer; larger values are Long</td></tr>
<tr><td>Hex integer</td><td><code>&amp;HFF</code></td><td>Hexadecimal literal</td></tr>
<tr><td>Long suffix</td><td><code>42&amp;</code>, <code>&amp;HFF&amp;</code></td><td>Force Long type</td></tr>
<tr><td>Floating-point</td><td><code>3.14</code>, <code>1.5E10</code></td><td>Double by default</td></tr>
<tr><td>Single suffix</td><td><code>3.14!</code></td><td>Force Single type</td></tr>
<tr><td>Double suffix</td><td><code>3.14#</code></td><td>Force Double type</td></tr>
</table>
<h3>Type Promotion</h3>
<p>When mixing types in expressions, values are automatically promoted to a
common type: Integer -&gt; Long -&gt; Single -&gt; Double. Strings are
not automatically converted to numbers (use <code>VAL</code> and
<code>STR$</code>).</p>
<!-- ============================================================ -->
<h2 id="operators">2. Operators</h2>
<!-- ============================================================ -->
<p>Operators listed from highest precedence (evaluated first) to lowest
precedence (evaluated last).</p>
<table>
<tr>
<th>Precedence</th>
<th>Operator</th>
<th>Description</th>
</tr>
<tr>
<td>1 (highest)</td>
<td><code>^</code></td>
<td>Exponentiation</td>
</tr>
<tr>
<td>2</td>
<td><code>-</code> (unary)</td>
<td>Negation</td>
</tr>
<tr>
<td>3</td>
<td><code>*</code> &nbsp; <code>/</code> &nbsp; <code>\</code>
&nbsp; <code>MOD</code></td>
<td>Multiplication, float division, integer division, modulus</td>
</tr>
<tr>
<td>4</td>
<td><code>+</code> &nbsp; <code>-</code></td>
<td>Addition, subtraction</td>
</tr>
<tr>
<td>5</td>
<td><code>&amp;</code></td>
<td>String concatenation</td>
</tr>
<tr>
<td>6</td>
<td><code>=</code> &nbsp; <code>&lt;&gt;</code> &nbsp; <code>&lt;</code>
&nbsp; <code>&gt;</code> &nbsp; <code>&lt;=</code> &nbsp;
<code>&gt;=</code></td>
<td>Comparison (returns Boolean)</td>
</tr>
<tr>
<td>7</td>
<td><code>NOT</code></td>
<td>Logical/bitwise NOT</td>
</tr>
<tr>
<td>8</td>
<td><code>AND</code></td>
<td>Logical/bitwise AND</td>
</tr>
<tr>
<td>9</td>
<td><code>XOR</code></td>
<td>Logical/bitwise XOR</td>
</tr>
<tr>
<td>10</td>
<td><code>OR</code></td>
<td>Logical/bitwise OR</td>
</tr>
<tr>
<td>11</td>
<td><code>EQV</code></td>
<td>Logical/bitwise equivalence</td>
</tr>
<tr>
<td>12 (lowest)</td>
<td><code>IMP</code></td>
<td>Logical/bitwise implication</td>
</tr>
</table>
<h3>String Concatenation</h3>
<p>Use <code>&amp;</code> to concatenate strings. The <code>+</code> operator
also concatenates when both operands are strings.</p>
<pre>
result$ = "Hello" &amp; " " &amp; "World"
result$ = firstName$ &amp; " " &amp; lastName$
</pre>
<!-- ============================================================ -->
<h2 id="statements">3. Statements</h2>
<!-- ============================================================ -->
<p>Multiple statements can appear on one line separated by <code>:</code>.
Lines can be continued with <code>_</code> at the end. Comments start with
<code>'</code> or <code>REM</code>.</p>
<!-- ----- DIM ----- -->
<h3 id="stmt-dim">DIM</h3>
<p>Declares variables and arrays with an explicit type.</p>
<pre>
DIM <i>variable</i> AS <i>type</i>
DIM <i>variable</i>(<i>upperBound</i>) AS <i>type</i>
DIM <i>variable</i>(<i>lower</i> TO <i>upper</i>) AS <i>type</i>
DIM <i>variable</i>(<i>dim1</i>, <i>dim2</i>, ...) AS <i>type</i>
DIM <i>variable</i> AS <i>UdtName</i>
DIM <i>variable</i> AS STRING * <i>n</i>
DIM SHARED <i>variable</i> AS <i>type</i>
</pre>
<p>Examples:</p>
<pre>
Dim name As String
Dim count As Integer
Dim values(100) As Double
Dim matrix(1 To 10, 1 To 10) As Single
Dim Shared globalFlag As Boolean
Dim record As PersonType
Dim fixedStr As String * 20
</pre>
<div class="note">
<code>DIM SHARED</code> makes a variable accessible from all procedures
without passing it as a parameter.
</div>
<!-- ----- REDIM ----- -->
<h3 id="stmt-redim">REDIM</h3>
<p>Reallocates a dynamic array, optionally preserving existing data.</p>
<pre>
REDIM <i>array</i>(<i>newBounds</i>) AS <i>type</i>
REDIM PRESERVE <i>array</i>(<i>newBounds</i>) AS <i>type</i>
</pre>
<pre>
ReDim items(newSize) As String
ReDim Preserve scores(1 To newCount) As Integer
</pre>
<!-- ----- CONST ----- -->
<h3 id="stmt-const">CONST</h3>
<p>Declares a named constant. The value must be a literal (integer, float,
string, or boolean).</p>
<pre>
CONST <i>name</i> = <i>value</i>
</pre>
<pre>
Const MAX_SIZE = 100
Const PI = 3.14159265
Const APP_NAME = "DVX App"
Const DEBUG_MODE = True
</pre>
<!-- ----- TYPE ----- -->
<h3 id="stmt-type">TYPE...END TYPE</h3>
<p>Defines a user-defined type (record/structure).</p>
<pre>
TYPE <i>TypeName</i>
<i>fieldName</i> AS <i>type</i>
...
END TYPE
</pre>
<pre>
Type PersonType
firstName As String
lastName As String
age As Integer
End Type
Dim p As PersonType
p.firstName = "Scott"
p.age = 30
</pre>
<p>UDT fields can themselves be UDTs (nested types).</p>
<!-- ----- IF ----- -->
<h3 id="stmt-if">IF...THEN...ELSE...END IF</h3>
<p>Conditional execution. Supports single-line and multi-line forms.</p>
<h4>Single-line form:</h4>
<pre>
IF <i>condition</i> THEN <i>statement</i>
IF <i>condition</i> THEN <i>statement</i> ELSE <i>statement</i>
</pre>
<h4>Multi-line form:</h4>
<pre>
IF <i>condition</i> THEN
<i>statements</i>
ELSEIF <i>condition</i> THEN
<i>statements</i>
ELSE
<i>statements</i>
END IF
</pre>
<pre>
If x > 10 Then
Print "Large"
ElseIf x > 5 Then
Print "Medium"
Else
Print "Small"
End If
If ready Then Print "Go!"
</pre>
<!-- ----- SELECT CASE ----- -->
<h3 id="stmt-select">SELECT CASE</h3>
<p>Multi-way branch based on an expression value.</p>
<pre>
SELECT CASE <i>expression</i>
CASE <i>value</i>
<i>statements</i>
CASE <i>value1</i>, <i>value2</i>
<i>statements</i>
CASE <i>low</i> TO <i>high</i>
<i>statements</i>
CASE IS <i>operator value</i>
<i>statements</i>
CASE ELSE
<i>statements</i>
END SELECT
</pre>
<pre>
Select Case grade
Case 90 To 100
Print "A"
Case 80 To 89
Print "B"
Case Is >= 70
Print "C"
Case 60, 65
Print "D (borderline)"
Case Else
Print "F"
End Select
</pre>
<p>CASE items can be combined with commas. The <code>IS</code> keyword allows
comparison operators: <code>&lt;</code>, <code>&gt;</code>,
<code>&lt;=</code>, <code>&gt;=</code>, <code>=</code>,
<code>&lt;&gt;</code>.</p>
<!-- ----- FOR/NEXT ----- -->
<h3 id="stmt-for">FOR...NEXT</h3>
<p>Counted loop with an optional step value.</p>
<pre>
FOR <i>variable</i> = <i>start</i> TO <i>limit</i> [STEP <i>step</i>]
<i>statements</i>
NEXT [<i>variable</i>]
</pre>
<pre>
For i = 1 To 10
Print i
Next i
For x = 10 To 0 Step -2
Print x
Next
</pre>
<p>The variable name after <code>NEXT</code> is optional. Use
<code>EXIT FOR</code> to break out early.</p>
<!-- ----- DO/LOOP ----- -->
<h3 id="stmt-do">DO...LOOP</h3>
<p>General-purpose loop with pre-test, post-test, or infinite forms.</p>
<pre>
DO [WHILE <i>condition</i> | UNTIL <i>condition</i>]
<i>statements</i>
LOOP [WHILE <i>condition</i> | UNTIL <i>condition</i>]
</pre>
<pre>
' Pre-test
Do While count < 10
count = count + 1
Loop
' Post-test
Do
line$ = ReadLine()
Loop Until line$ = "quit"
' Infinite loop (exit with EXIT DO)
Do
DoEvents
If done Then Exit Do
Loop
</pre>
<!-- ----- WHILE/WEND ----- -->
<h3 id="stmt-while">WHILE...WEND</h3>
<p>Simple pre-test loop (legacy form; prefer <code>DO...LOOP</code>).</p>
<pre>
WHILE <i>condition</i>
<i>statements</i>
WEND
</pre>
<pre>
While Not EOF(1)
Line Input #1, line$
Print line$
Wend
</pre>
<!-- ----- SUB ----- -->
<h3 id="stmt-sub">SUB...END SUB</h3>
<p>Defines a subroutine (no return value).</p>
<pre>
SUB <i>name</i> ([BYVAL] <i>param</i> AS <i>type</i>, ...)
<i>statements</i>
END SUB
</pre>
<pre>
Sub Greet(ByVal name As String)
Print "Hello, " &amp; name
End Sub
</pre>
<p>Parameters are passed <code>ByRef</code> by default. Use
<code>ByVal</code> for value semantics. Use <code>EXIT SUB</code> to
return early.</p>
<!-- ----- FUNCTION ----- -->
<h3 id="stmt-function">FUNCTION...END FUNCTION</h3>
<p>Defines a function with a return value.</p>
<pre>
FUNCTION <i>name</i> ([BYVAL] <i>param</i> AS <i>type</i>, ...) AS <i>returnType</i>
<i>statements</i>
<i>name</i> = <i>returnValue</i>
END FUNCTION
</pre>
<pre>
Function Square(ByVal n As Double) As Double
Square = n * n
End Function
</pre>
<p>Assign to the function name to set the return value. Use
<code>EXIT FUNCTION</code> to return early.</p>
<!-- ----- DEF FN ----- -->
<h3 id="stmt-def">DEF FN</h3>
<p>Defines a single-expression function.</p>
<pre>
DEF FN<i>name</i>(<i>params</i>) = <i>expression</i>
</pre>
<pre>
Def FnSquare(x) = x * x
Print FnSquare(5) ' prints 25
</pre>
<!-- ----- EXIT ----- -->
<h3 id="stmt-exit">EXIT</h3>
<p>Exits the current block early.</p>
<pre>
EXIT FOR
EXIT DO
EXIT SUB
EXIT FUNCTION
</pre>
<!-- ----- CALL ----- -->
<h3 id="stmt-call">CALL</h3>
<p>Explicitly calls a subroutine or function. The return value (if any) is
discarded.</p>
<pre>
CALL <i>name</i>
CALL <i>name</i>(<i>args</i>)
</pre>
<p>Normally you can omit <code>CALL</code> and just use the name directly.</p>
<!-- ----- GOTO/GOSUB ----- -->
<h3 id="stmt-goto">GOTO / GOSUB / RETURN</h3>
<pre>
GOTO <i>label</i>
GOSUB <i>label</i>
RETURN
</pre>
<p><code>GOSUB</code> pushes the return address, executes code at the label,
and <code>RETURN</code> jumps back. At module level, <code>RETURN</code>
returns from a GOSUB. Inside a SUB/FUNCTION, <code>RETURN</code> returns
from the procedure.</p>
<pre>
GoSub Initialize
Print "Done"
End
Initialize:
count = 0
name$ = ""
Return
</pre>
<!-- ----- ON ----- -->
<h3 id="stmt-on">ON...GOTO / ON...GOSUB</h3>
<p>Computed branch based on an integer expression.</p>
<pre>
ON <i>expression</i> GOTO <i>label1</i>, <i>label2</i>, ...
ON <i>expression</i> GOSUB <i>label1</i>, <i>label2</i>, ...
</pre>
<p>If the expression evaluates to 1, control goes to the first label; 2, the
second; and so on. If out of range, execution falls through.</p>
<!-- ----- PRINT ----- -->
<h3 id="stmt-print">PRINT</h3>
<p>Outputs text to the console or to a file channel.</p>
<pre>
PRINT [<i>expression</i>] [{; | ,} <i>expression</i>] ...
PRINT #<i>channel</i>, <i>expression</i>
PRINT USING <i>format$</i>; <i>expression</i> [; <i>expression</i>] ...
</pre>
<ul>
<li><code>;</code> between items -- no separator (items are concatenated)</li>
<li><code>,</code> between items -- advance to the next 14-column tab zone</li>
<li>Trailing <code>;</code> or <code>,</code> suppresses the newline</li>
<li><code>?</code> is an alias for <code>PRINT</code></li>
</ul>
<p>Special functions inside PRINT:</p>
<ul>
<li><code>SPC(<i>n</i>)</code> -- print <i>n</i> spaces</li>
<li><code>TAB(<i>n</i>)</code> -- advance to column <i>n</i></li>
</ul>
<pre>
Print "Name:"; Tab(20); name$
Print Using "###.##"; total
Print #1, "Written to file"
</pre>
<!-- ----- INPUT ----- -->
<h3 id="stmt-input">INPUT</h3>
<p>Reads a line of text from the user or from a file channel.</p>
<pre>
INPUT <i>variable</i>
INPUT "<i>prompt</i>"; <i>variable</i>
INPUT #<i>channel</i>, <i>variable</i>
</pre>
<pre>
Input "Enter your name: "; name$
Input #1, line$
</pre>
<!-- ----- DATA/READ/RESTORE ----- -->
<h3 id="stmt-data">DATA / READ / RESTORE</h3>
<p>Inline data pool for constants.</p>
<pre>
DATA <i>value1</i>, <i>value2</i>, "<i>string</i>", ...
READ <i>variable1</i>, <i>variable2</i>, ...
RESTORE
</pre>
<p><code>DATA</code> statements define a pool of values. <code>READ</code>
reads the next value from the pool into a variable. <code>RESTORE</code>
resets the read pointer to the beginning.</p>
<pre>
Data 10, 20, 30, "Hello"
Read a, b, c, msg$
Print a; b; c; msg$
Restore
</pre>
<!-- ----- Assignment ----- -->
<h3 id="stmt-assign">Assignment</h3>
<p>Assigns a value to a variable, array element, or UDT field.</p>
<pre>
<i>variable</i> = <i>expression</i>
<i>array</i>(<i>index</i>) = <i>expression</i>
<i>udt</i>.<i>field</i> = <i>expression</i>
LET <i>variable</i> = <i>expression</i>
</pre>
<p>The <code>LET</code> keyword is optional and supported for
compatibility.</p>
<!-- ----- SWAP ----- -->
<h3 id="stmt-swap">SWAP</h3>
<p>Exchanges the values of two variables.</p>
<pre>
SWAP <i>variable1</i>, <i>variable2</i>
</pre>
<pre>
Swap a, b
</pre>
<!-- ----- ERASE ----- -->
<h3 id="stmt-erase">ERASE</h3>
<p>Frees the memory of an array and resets it.</p>
<pre>
ERASE <i>arrayName</i>
</pre>
<!-- ----- OPTION ----- -->
<h3 id="stmt-option">OPTION</h3>
<p>Sets compiler options. Must appear before any executable code.</p>
<pre>
OPTION BASE 0 ' Arrays start at index 0 (default)
OPTION BASE 1 ' Arrays start at index 1
OPTION COMPARE BINARY ' Case-sensitive string comparisons (default)
OPTION COMPARE TEXT ' Case-insensitive string comparisons
OPTION EXPLICIT ' All variables must be declared with DIM
</pre>
<!-- ----- DEFtype ----- -->
<h3 id="stmt-deftype">DEFtype Statements</h3>
<p>Set the default type for variables based on their first letter.</p>
<pre>
DEFINT <i>letterRange</i>
DEFLNG <i>letterRange</i>
DEFSNG <i>letterRange</i>
DEFDBL <i>letterRange</i>
DEFSTR <i>letterRange</i>
</pre>
<pre>
DefInt I-N ' Variables starting with I through N default to Integer
DefStr S ' Variables starting with S default to String
</pre>
<!-- ----- STATIC ----- -->
<h3 id="stmt-static">STATIC</h3>
<p>Declares a local variable that retains its value between calls.</p>
<pre>
STATIC <i>variable</i> AS <i>type</i>
</pre>
<pre>
Sub Counter()
Static count As Integer
count = count + 1
Print count
End Sub
</pre>
<!-- ----- Error Handling ----- -->
<h3 id="stmt-error">Error Handling</h3>
<pre>
ON ERROR GOTO <i>label</i> ' Enable error handler
ON ERROR GOTO 0 ' Disable error handler
RESUME ' Retry the statement that caused the error
RESUME NEXT ' Continue at the next statement after the error
ERROR <i>n</i> ' Raise a runtime error with error number <i>n</i>
</pre>
<p>The <code>ERR</code> keyword returns the current error number in
expressions.</p>
<pre>
On Error GoTo ErrorHandler
Open "missing.txt" For Input As #1
Exit Sub
ErrorHandler:
Print "Error number:"; Err
Resume Next
</pre>
<!-- ----- SHELL ----- -->
<h3 id="stmt-shell">SHELL</h3>
<p>Executes an operating system command.</p>
<pre>
SHELL "<i>command</i>"
</pre>
<p>When used as a function, returns the exit code of the command.</p>
<pre>
Shell "DIR /B"
exitCode = Shell("COPY A.TXT B.TXT")
</pre>
<!-- ----- SLEEP ----- -->
<h3 id="stmt-sleep">SLEEP</h3>
<p>Pauses execution for a specified number of seconds.</p>
<pre>
SLEEP <i>seconds</i>
</pre>
<!-- ----- RANDOMIZE ----- -->
<h3 id="stmt-randomize">RANDOMIZE</h3>
<p>Seeds the random number generator.</p>
<pre>
RANDOMIZE <i>seed</i>
RANDOMIZE TIMER ' Seed from system clock
</pre>
<!-- ----- END ----- -->
<h3 id="stmt-end">END</h3>
<p>Terminates program execution immediately.</p>
<pre>
END
</pre>
<!-- ----- DECLARE ----- -->
<h3 id="stmt-declare">DECLARE</h3>
<p>Forward-declares a SUB or FUNCTION. Required when a procedure is called
before it is defined.</p>
<pre>
DECLARE SUB <i>name</i> ([BYVAL] <i>param</i> AS <i>type</i>, ...)
DECLARE FUNCTION <i>name</i> ([BYVAL] <i>param</i> AS <i>type</i>, ...) AS <i>returnType</i>
</pre>
<!-- ----- DECLARE LIBRARY ----- -->
<h3 id="stmt-declarelib">DECLARE LIBRARY</h3>
<p>Declares external native functions from a dynamically loaded library.
This allows BASIC programs to call functions exported by DXE libraries.</p>
<pre>
DECLARE LIBRARY "<i>libraryName</i>"
DECLARE SUB <i>name</i> ([BYVAL] <i>param</i> AS <i>type</i>, ...)
DECLARE FUNCTION <i>name</i> ([BYVAL] <i>param</i> AS <i>type</i>, ...) AS <i>returnType</i>
END DECLARE
</pre>
<pre>
Declare Library "rs232"
Declare Function ComOpen(ByVal port As Integer) As Integer
Declare Sub ComClose(ByVal port As Integer)
Declare Sub ComSend(ByVal port As Integer, ByVal data$ As String)
End Declare
</pre>
<!-- ============================================================ -->
<h2 id="file-io">4. File I/O</h2>
<!-- ============================================================ -->
<h3>OPEN</h3>
<p>Opens a file for reading, writing, or appending.</p>
<pre>
OPEN <i>filename$</i> FOR INPUT AS #<i>channel</i>
OPEN <i>filename$</i> FOR OUTPUT AS #<i>channel</i>
OPEN <i>filename$</i> FOR APPEND AS #<i>channel</i>
OPEN <i>filename$</i> FOR RANDOM AS #<i>channel</i> [LEN = <i>recordSize</i>]
OPEN <i>filename$</i> FOR BINARY AS #<i>channel</i>
</pre>
<table>
<tr><th>Mode</th><th>Description</th></tr>
<tr><td><code>INPUT</code></td><td>Open for sequential reading. File must exist.</td></tr>
<tr><td><code>OUTPUT</code></td><td>Open for sequential writing. Creates or truncates.</td></tr>
<tr><td><code>APPEND</code></td><td>Open for sequential writing at end of file.</td></tr>
<tr><td><code>RANDOM</code></td><td>Open for random-access record I/O.</td></tr>
<tr><td><code>BINARY</code></td><td>Open for raw binary I/O.</td></tr>
</table>
<h3>CLOSE</h3>
<pre>
CLOSE #<i>channel</i>
</pre>
<h3>PRINT #</h3>
<p>Writes text to a file.</p>
<pre>
PRINT #<i>channel</i>, <i>expression</i>
</pre>
<h3>INPUT #</h3>
<p>Reads comma-delimited data from a file.</p>
<pre>
INPUT #<i>channel</i>, <i>variable</i>
</pre>
<h3>LINE INPUT #</h3>
<p>Reads an entire line from a file into a string variable.</p>
<pre>
LINE INPUT #<i>channel</i>, <i>variable$</i>
</pre>
<h3>WRITE #</h3>
<p>Writes comma-delimited data to a file. Strings are enclosed in quotes,
numbers are undecorated. Each statement writes a newline at the end.</p>
<pre>
WRITE #<i>channel</i>, <i>expr1</i>, <i>expr2</i>, ...
</pre>
<pre>
Write #1, "Scott", 42, 3.14
' Output: "Scott",42,3.14
</pre>
<h3>GET / PUT</h3>
<p>Read and write records in RANDOM or BINARY mode files.</p>
<pre>
GET #<i>channel</i>, [<i>recordNum</i>], <i>variable</i>
PUT #<i>channel</i>, [<i>recordNum</i>], <i>variable</i>
</pre>
<h3>SEEK</h3>
<p>Sets the file position. As a function, returns the current position.</p>
<pre>
SEEK #<i>channel</i>, <i>position</i> ' Statement: set position
<i>pos</i> = SEEK(<i>channel</i>) ' Function: get current position
</pre>
<!-- ============================================================ -->
<h2 id="builtin-functions">5. Built-in Functions</h2>
<!-- ============================================================ -->
<!-- ----- String Functions ----- -->
<h3 id="func-string">String Functions</h3>
<table>
<tr>
<th>Function</th>
<th>Args</th>
<th>Returns</th>
<th>Description</th>
</tr>
<tr>
<td><code>ASC(<i>s$</i>)</code></td>
<td>1</td>
<td>Integer</td>
<td>Returns the ASCII code of the first character of <i>s$</i>.</td>
</tr>
<tr>
<td><code>CHR$(<i>n</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Returns the character with ASCII code <i>n</i>.</td>
</tr>
<tr>
<td><code>FORMAT$(<i>value</i>, <i>fmt$</i>)</code></td>
<td>2</td>
<td>String</td>
<td>Formats a numeric value using the format string <i>fmt$</i>.</td>
</tr>
<tr>
<td><code>HEX$(<i>n</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Returns the hexadecimal representation of <i>n</i>.</td>
</tr>
<tr>
<td><code>INSTR(<i>s$</i>, <i>find$</i>)</code></td>
<td>2-3</td>
<td>Integer</td>
<td>Returns the position of <i>find$</i> in <i>s$</i> (1-based). Optionally
takes a starting position as the first argument:
<code>INSTR(<i>start</i>, <i>s$</i>, <i>find$</i>)</code>. Returns 0 if
not found.</td>
</tr>
<tr>
<td><code>LCASE$(<i>s$</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Converts <i>s$</i> to lowercase.</td>
</tr>
<tr>
<td><code>LEFT$(<i>s$</i>, <i>n</i>)</code></td>
<td>2</td>
<td>String</td>
<td>Returns the leftmost <i>n</i> characters of <i>s$</i>.</td>
</tr>
<tr>
<td><code>LEN(<i>s$</i>)</code></td>
<td>1</td>
<td>Integer</td>
<td>Returns the length of <i>s$</i>.</td>
</tr>
<tr>
<td><code>LTRIM$(<i>s$</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Removes leading spaces from <i>s$</i>.</td>
</tr>
<tr>
<td><code>MID$(<i>s$</i>, <i>start</i> [, <i>length</i>])</code></td>
<td>2-3</td>
<td>String</td>
<td>Returns a substring starting at position <i>start</i> (1-based). If
<i>length</i> is omitted, returns from <i>start</i> to end.</td>
</tr>
<tr>
<td><code>RIGHT$(<i>s$</i>, <i>n</i>)</code></td>
<td>2</td>
<td>String</td>
<td>Returns the rightmost <i>n</i> characters of <i>s$</i>.</td>
</tr>
<tr>
<td><code>RTRIM$(<i>s$</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Removes trailing spaces from <i>s$</i>.</td>
</tr>
<tr>
<td><code>SPACE$(<i>n</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Returns a string of <i>n</i> spaces.</td>
</tr>
<tr>
<td><code>STR$(<i>n</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Converts number <i>n</i> to its string representation.</td>
</tr>
<tr>
<td><code>STRING$(<i>n</i>, <i>char</i>)</code></td>
<td>2</td>
<td>String</td>
<td>Returns a string of <i>n</i> copies of <i>char</i> (ASCII code or
single-character string).</td>
</tr>
<tr>
<td><code>TRIM$(<i>s$</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Removes leading and trailing spaces from <i>s$</i>.</td>
</tr>
<tr>
<td><code>UCASE$(<i>s$</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Converts <i>s$</i> to uppercase.</td>
</tr>
<tr>
<td><code>VAL(<i>s$</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Converts the string <i>s$</i> to a numeric value.</td>
</tr>
</table>
<h4>MID$ Assignment</h4>
<p><code>MID$</code> can also be used on the left side of an assignment to
replace a portion of a string:</p>
<pre>
Mid$(s$, 3, 2) = "XY" ' Replace 2 characters starting at position 3
</pre>
<!-- ----- Math Functions ----- -->
<h3 id="func-math">Math Functions</h3>
<table>
<tr>
<th>Function</th>
<th>Args</th>
<th>Returns</th>
<th>Description</th>
</tr>
<tr>
<td><code>ABS(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Absolute value of <i>n</i>.</td>
</tr>
<tr>
<td><code>ATN(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Arctangent of <i>n</i> (in radians).</td>
</tr>
<tr>
<td><code>COS(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Cosine of <i>n</i> (radians).</td>
</tr>
<tr>
<td><code>EXP(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Returns e raised to the power <i>n</i>.</td>
</tr>
<tr>
<td><code>FIX(<i>n</i>)</code></td>
<td>1</td>
<td>Integer</td>
<td>Truncates <i>n</i> toward zero (removes the fractional part).</td>
</tr>
<tr>
<td><code>INT(<i>n</i>)</code></td>
<td>1</td>
<td>Integer</td>
<td>Returns the largest integer less than or equal to <i>n</i> (floor).</td>
</tr>
<tr>
<td><code>LOG(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Natural logarithm (base e) of <i>n</i>.</td>
</tr>
<tr>
<td><code>RND[(<i>n</i>)]</code></td>
<td>0-1</td>
<td>Double</td>
<td>Returns a random number between 0 (inclusive) and 1 (exclusive).
With a negative argument, seeds and returns. With 0, returns the
previous value.</td>
</tr>
<tr>
<td><code>SGN(<i>n</i>)</code></td>
<td>1</td>
<td>Integer</td>
<td>Returns the sign of <i>n</i>: -1, 0, or 1.</td>
</tr>
<tr>
<td><code>SIN(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Sine of <i>n</i> (radians).</td>
</tr>
<tr>
<td><code>SQR(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Square root of <i>n</i>.</td>
</tr>
<tr>
<td><code>TAN(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Tangent of <i>n</i> (radians).</td>
</tr>
<tr>
<td><code>TIMER</code></td>
<td>0</td>
<td>Double</td>
<td>Returns the number of seconds since midnight.</td>
</tr>
</table>
<!-- ----- Conversion Functions ----- -->
<h3 id="func-conversion">Conversion Functions</h3>
<table>
<tr>
<th>Function</th>
<th>Args</th>
<th>Returns</th>
<th>Description</th>
</tr>
<tr>
<td><code>CDBL(<i>n</i>)</code></td>
<td>1</td>
<td>Double</td>
<td>Converts <i>n</i> to Double.</td>
</tr>
<tr>
<td><code>CINT(<i>n</i>)</code></td>
<td>1</td>
<td>Integer</td>
<td>Converts <i>n</i> to Integer (with banker's rounding).</td>
</tr>
<tr>
<td><code>CLNG(<i>n</i>)</code></td>
<td>1</td>
<td>Long</td>
<td>Converts <i>n</i> to Long.</td>
</tr>
<tr>
<td><code>CSNG(<i>n</i>)</code></td>
<td>1</td>
<td>Single</td>
<td>Converts <i>n</i> to Single.</td>
</tr>
<tr>
<td><code>CSTR(<i>n</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Converts <i>n</i> to its String representation.</td>
</tr>
</table>
<!-- ----- File I/O Functions ----- -->
<h3 id="func-fileio">File I/O Functions</h3>
<table>
<tr>
<th>Function</th>
<th>Args</th>
<th>Returns</th>
<th>Description</th>
</tr>
<tr>
<td><code>EOF(<i>channel</i>)</code></td>
<td>1</td>
<td>Boolean</td>
<td>Returns True if the file pointer is at end of file.</td>
</tr>
<tr>
<td><code>FREEFILE</code></td>
<td>0</td>
<td>Integer</td>
<td>Returns the next available file channel number.</td>
</tr>
<tr>
<td><code>INPUT$(<i>n</i>, <i>#channel</i>)</code></td>
<td>2</td>
<td>String</td>
<td>Reads <i>n</i> characters from the file and returns them as a string.</td>
</tr>
<tr>
<td><code>LOC(<i>channel</i>)</code></td>
<td>1</td>
<td>Long</td>
<td>Returns the current read/write position in the file.</td>
</tr>
<tr>
<td><code>LOF(<i>channel</i>)</code></td>
<td>1</td>
<td>Long</td>
<td>Returns the length of the file in bytes.</td>
</tr>
<tr>
<td><code>SEEK(<i>channel</i>)</code></td>
<td>1</td>
<td>Long</td>
<td>Returns the current file position (function form of SEEK).</td>
</tr>
<tr>
<td><code>LBOUND(<i>array</i> [, <i>dim</i>])</code></td>
<td>1-2</td>
<td>Integer</td>
<td>Returns the lower bound of an array dimension.</td>
</tr>
<tr>
<td><code>UBOUND(<i>array</i> [, <i>dim</i>])</code></td>
<td>1-2</td>
<td>Integer</td>
<td>Returns the upper bound of an array dimension.</td>
</tr>
</table>
<!-- ----- Miscellaneous Functions ----- -->
<h3 id="func-misc">Miscellaneous Functions</h3>
<table>
<tr>
<th>Function</th>
<th>Args</th>
<th>Returns</th>
<th>Description</th>
</tr>
<tr>
<td><code>DATE$</code></td>
<td>0</td>
<td>String</td>
<td>Returns the current date as "MM-DD-YYYY".</td>
</tr>
<tr>
<td><code>TIME$</code></td>
<td>0</td>
<td>String</td>
<td>Returns the current time as "HH:MM:SS".</td>
</tr>
<tr>
<td><code>ENVIRON$(<i>name$</i>)</code></td>
<td>1</td>
<td>String</td>
<td>Returns the value of the environment variable <i>name$</i>.</td>
</tr>
<tr>
<td><code>ERR</code></td>
<td>0</td>
<td>Integer</td>
<td>Returns the current runtime error number (0 if no error).</td>
</tr>
</table>
<!-- ============================================================ -->
<h2 id="form-controls">6. Form and Control Statements</h2>
<!-- ============================================================ -->
<p>DVX BASIC supports Visual Basic-style forms and controls for building
graphical user interfaces. Forms are defined in <code>.frm</code> files and
loaded at runtime.</p>
<h3>Loading and Unloading Forms</h3>
<pre>
LOAD <i>FormName</i>
UNLOAD <i>FormName</i>
</pre>
<p><code>LOAD</code> creates the form and its controls in memory.
<code>UNLOAD</code> destroys the form and frees its resources.</p>
<h3>Showing and Hiding Forms</h3>
<pre>
<i>FormName</i>.Show [<i>modal</i>]
<i>FormName</i>.Hide
Me.Show [<i>modal</i>]
Me.Hide
</pre>
<p>Pass <code>vbModal</code> (1) to <code>Show</code> for a modal dialog.</p>
<pre>
Form2.Show vbModal
Me.Hide
</pre>
<h3>Property Access</h3>
<p>Read and write control properties using dot notation:</p>
<pre>
<i>ControlName</i>.<i>Property</i> = <i>value</i>
<i>value</i> = <i>ControlName</i>.<i>Property</i>
</pre>
<pre>
Text1.Text = "Hello"
label1.Caption = "Name: " &amp; name$
x = Text1.Left
</pre>
<h3>Method Calls</h3>
<pre>
<i>ControlName</i>.<i>Method</i> [<i>args</i>]
</pre>
<pre>
List1.AddItem "New entry"
List1.Clear
</pre>
<h3>Me Keyword</h3>
<p><code>Me</code> refers to the current form. Use it to access the form's
own properties, controls, and methods from within event handlers.</p>
<pre>
Me.Caption = "Updated Title"
Me.Text1.Text = ""
Me.Hide
</pre>
<h3>Control Arrays</h3>
<p>Multiple controls can share a name with unique indices. Access individual
controls with parenthesized indices:</p>
<pre>
Option1(0).Value = True
Label1(idx).Caption = "Item " &amp; Str$(idx)
Me.Label1(i).Visible = True
</pre>
<h3>DoEvents</h3>
<p>Yields control to the DVX event loop, allowing the GUI to process pending
events. Call this in long-running loops to keep the UI responsive.</p>
<pre>
DOEVENTS
</pre>
<pre>
For i = 1 To 10000
' process data
If i Mod 100 = 0 Then DoEvents
Next
</pre>
<h3>MsgBox</h3>
<p>Displays a message box dialog. Can be used as a statement (discards
result) or as a function (returns the button clicked).</p>
<pre>
MSGBOX <i>message$</i> [, <i>flags</i>]
<i>result</i> = MSGBOX(<i>message$</i> [, <i>flags</i>])
</pre>
<pre>
MsgBox "Operation complete"
answer = MsgBox("Continue?", vbYesNo + vbQuestion)
If answer = vbYes Then
' proceed
End If
</pre>
<h3>InputBox$</h3>
<p>Displays an input dialog and returns the user's text entry.</p>
<pre>
<i>result$</i> = INPUTBOX$(<i>prompt$</i> [, <i>title$</i> [, <i>default$</i>]])
</pre>
<pre>
name$ = InputBox$("Enter your name:", "Name Entry", "")
</pre>
<h3>Event Handler Convention</h3>
<p>Event handlers are named <code><i>ControlName</i>_<i>EventName</i></code>
and defined as SUBs:</p>
<pre>
Sub Command1_Click()
MsgBox "Button clicked!"
End Sub
Sub Form_Load()
Me.Caption = "My App"
End Sub
Sub Text1_Change()
Label1.Caption = "You typed: " &amp; Text1.Text
End Sub
</pre>
<p>Common events:</p>
<table>
<tr><th>Event</th><th>Description</th></tr>
<tr><td><code>Click</code></td><td>Control was clicked</td></tr>
<tr><td><code>DblClick</code></td><td>Control was double-clicked</td></tr>
<tr><td><code>Change</code></td><td>Control value/text changed</td></tr>
<tr><td><code>KeyPress</code></td><td>Key was pressed (receives key code)</td></tr>
<tr><td><code>KeyDown</code></td><td>Key went down (receives key code and shift state)</td></tr>
<tr><td><code>KeyUp</code></td><td>Key was released</td></tr>
<tr><td><code>MouseDown</code></td><td>Mouse button pressed</td></tr>
<tr><td><code>MouseUp</code></td><td>Mouse button released</td></tr>
<tr><td><code>MouseMove</code></td><td>Mouse moved over control</td></tr>
<tr><td><code>GotFocus</code></td><td>Control received input focus</td></tr>
<tr><td><code>LostFocus</code></td><td>Control lost input focus</td></tr>
<tr><td><code>Form_Load</code></td><td>Form is being loaded</td></tr>
<tr><td><code>Form_Unload</code></td><td>Form is being unloaded</td></tr>
<tr><td><code>Form_Resize</code></td><td>Form was resized</td></tr>
<tr><td><code>Timer</code></td><td>Timer interval elapsed</td></tr>
</table>
<!-- ============================================================ -->
<h2 id="sql-functions">7. SQL Functions</h2>
<!-- ============================================================ -->
<p>DVX BASIC includes built-in SQLite database support through a set of SQL
functions. All functions use database handles and result set handles
(integers) returned by <code>SQLOpen</code> and <code>SQLQuery</code>.</p>
<h3>Opening and Closing Databases</h3>
<h4>SQLOpen</h4>
<p>Opens a SQLite database file and returns a database handle.</p>
<pre>
<i>db</i> = SQLOPEN(<i>path$</i>)
</pre>
<pre>
db = SQLOpen(App.Data &amp; "\mydata.db")
</pre>
<h4>SQLClose</h4>
<p>Closes an open database.</p>
<pre>
SQLCLOSE <i>db</i>
</pre>
<h3>Executing SQL</h3>
<h4>SQLExec</h4>
<p>Executes a SQL statement that does not return data (INSERT, UPDATE,
DELETE, CREATE TABLE, etc.). Can be used as a statement or as a function
returning a Boolean success flag.</p>
<pre>
SQLEXEC <i>db</i>, <i>sql$</i>
<i>ok</i> = SQLEXEC(<i>db</i>, <i>sql$</i>)
</pre>
<pre>
SQLExec db, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)"
SQLExec db, "INSERT INTO users (name) VALUES ('Scott')"
ok = SQLExec(db, "DELETE FROM users WHERE id = 5")
</pre>
<h4>SQLAffected</h4>
<p>Returns the number of rows affected by the last INSERT, UPDATE, or DELETE.</p>
<pre>
<i>count</i> = SQLAFFECTED(<i>db</i>)
</pre>
<h3>Querying Data</h3>
<h4>SQLQuery</h4>
<p>Executes a SELECT query and returns a result set handle.</p>
<pre>
<i>rs</i> = SQLQUERY(<i>db</i>, <i>sql$</i>)
</pre>
<pre>
rs = SQLQuery(db, "SELECT id, name FROM users ORDER BY name")
</pre>
<h4>SQLNext</h4>
<p>Advances to the next row in the result set. Can be used as a statement or
as a function returning True if a row is available.</p>
<pre>
SQLNEXT <i>rs</i>
<i>hasRow</i> = SQLNEXT(<i>rs</i>)
</pre>
<h4>SQLEof</h4>
<p>Returns True if there are no more rows in the result set.</p>
<pre>
<i>done</i> = SQLEOF(<i>rs</i>)
</pre>
<h3>Reading Fields</h3>
<h4>SQLField$</h4>
<p>Returns a field value as a string. The field can be specified by column
index (0-based) or by column name.</p>
<pre>
<i>value$</i> = SQLFIELD$(<i>rs</i>, <i>columnIndex</i>)
<i>value$</i> = SQLFIELD$(<i>rs</i>, "<i>columnName</i>")
</pre>
<pre>
name$ = SQLField$(rs, "name")
first$ = SQLField$(rs, 0)
</pre>
<h4>SQLFieldInt</h4>
<p>Returns a field value as an integer.</p>
<pre>
<i>value</i> = SQLFIELDINT(<i>rs</i>, <i>columnIndex</i>)
</pre>
<h4>SQLFieldDbl</h4>
<p>Returns a field value as a double.</p>
<pre>
<i>value#</i> = SQLFIELDDBL(<i>rs</i>, <i>columnIndex</i>)
</pre>
<h4>SQLFieldCount</h4>
<p>Returns the number of columns in the result set.</p>
<pre>
<i>count</i> = SQLFIELDCOUNT(<i>rs</i>)
</pre>
<h3>Result Set Cleanup</h3>
<h4>SQLFreeResult</h4>
<p>Frees a result set. Always call this when done iterating a query.</p>
<pre>
SQLFREERESULT <i>rs</i>
</pre>
<h3>Error Information</h3>
<h4>SQLError$</h4>
<p>Returns the last error message for the database.</p>
<pre>
<i>msg$</i> = SQLERROR$(<i>db</i>)
</pre>
<h3>Complete SQL Example</h3>
<pre>
Dim db As Long
Dim rs As Long
db = SQLOpen(App.Data &amp; "\contacts.db")
SQLExec db, "CREATE TABLE IF NOT EXISTS contacts (name TEXT, phone TEXT)"
SQLExec db, "INSERT INTO contacts VALUES ('Alice', '555-1234')"
rs = SQLQuery(db, "SELECT name, phone FROM contacts")
Do While Not SQLEof(rs)
SQLNext rs
Print SQLField$(rs, "name"); Tab(20); SQLField$(rs, "phone")
Loop
SQLFreeResult rs
SQLClose db
</pre>
<!-- ============================================================ -->
<h2 id="app-object">8. App Object</h2>
<!-- ============================================================ -->
<p>The <code>App</code> object provides read-only properties for the
application's directory paths.</p>
<table>
<tr>
<th>Property</th>
<th>Returns</th>
<th>Description</th>
</tr>
<tr>
<td><code>App.Path</code></td>
<td>String</td>
<td>The directory containing the application's executable.</td>
</tr>
<tr>
<td><code>App.Config</code></td>
<td>String</td>
<td>The directory for application configuration files.</td>
</tr>
<tr>
<td><code>App.Data</code></td>
<td>String</td>
<td>The directory for application data files (databases, etc.).</td>
</tr>
</table>
<pre>
configFile$ = App.Config &amp; "\settings.ini"
dbPath$ = App.Data &amp; "\myapp.db"
Print "Running from: " &amp; App.Path
</pre>
<!-- ============================================================ -->
<h2 id="ini-functions">9. INI Functions</h2>
<!-- ============================================================ -->
<p>DVX BASIC provides built-in functions for reading and writing standard INI
configuration files.</p>
<h3>IniRead</h3>
<p>Reads a value from an INI file. Returns the default value if the key is
not found.</p>
<pre>
<i>value$</i> = INIREAD(<i>file$</i>, <i>section$</i>, <i>key$</i>, <i>default$</i>)
</pre>
<pre>
name$ = IniRead(App.Config &amp; "\app.ini", "User", "Name", "Unknown")
fontSize = Val(IniRead(App.Config &amp; "\app.ini", "Display", "FontSize", "12"))
</pre>
<h3>IniWrite</h3>
<p>Writes a value to an INI file. Creates the file, section, or key if they
do not exist.</p>
<pre>
INIWRITE <i>file$</i>, <i>section$</i>, <i>key$</i>, <i>value$</i>
</pre>
<pre>
IniWrite App.Config &amp; "\app.ini", "User", "Name", "Scott"
IniWrite App.Config &amp; "\app.ini", "Display", "FontSize", Str$(fontSize)
</pre>
<!-- ============================================================ -->
<h2 id="predefined-constants">10. Predefined Constants</h2>
<!-- ============================================================ -->
<p>The following constants are predefined by the compiler and available in all
programs.</p>
<h3>MsgBox Button Style Flags</h3>
<table>
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
<tr><td><code>vbOKOnly</code></td><td>0</td><td>OK button only (default)</td></tr>
<tr><td><code>vbOKCancel</code></td><td>1</td><td>OK and Cancel buttons</td></tr>
<tr><td><code>vbYesNo</code></td><td>2</td><td>Yes and No buttons</td></tr>
<tr><td><code>vbYesNoCancel</code></td><td>3</td><td>Yes, No, and Cancel buttons</td></tr>
<tr><td><code>vbRetryCancel</code></td><td>4</td><td>Retry and Cancel buttons</td></tr>
</table>
<h3>MsgBox Icon Flags</h3>
<p>Add an icon flag to the button style to display an icon in the message
box.</p>
<table>
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
<tr><td><code>vbInformation</code></td><td>&amp;H10</td><td>Information icon</td></tr>
<tr><td><code>vbExclamation</code></td><td>&amp;H20</td><td>Warning icon</td></tr>
<tr><td><code>vbCritical</code></td><td>&amp;H30</td><td>Error/critical icon</td></tr>
<tr><td><code>vbQuestion</code></td><td>&amp;H40</td><td>Question mark icon</td></tr>
</table>
<h3>MsgBox Return Values</h3>
<table>
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
<tr><td><code>vbOK</code></td><td>1</td><td>User clicked OK</td></tr>
<tr><td><code>vbCancel</code></td><td>2</td><td>User clicked Cancel</td></tr>
<tr><td><code>vbYes</code></td><td>3</td><td>User clicked Yes</td></tr>
<tr><td><code>vbNo</code></td><td>4</td><td>User clicked No</td></tr>
<tr><td><code>vbRetry</code></td><td>5</td><td>User clicked Retry</td></tr>
</table>
<h3>Show Mode Flags</h3>
<table>
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
<tr><td><code>vbModal</code></td><td>1</td><td>Show form as modal dialog</td></tr>
</table>
<h3>Boolean Constants</h3>
<table>
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
<tr><td><code>True</code></td><td>-1</td><td>Boolean true</td></tr>
<tr><td><code>False</code></td><td>0</td><td>Boolean false</td></tr>
</table>
<hr>
<p><i>DVX BASIC Language Reference -- Generated from compiler source code.
Covers the lexer, parser, and VM opcode set as implemented.</i></p>
</body>
</html>