# dBase

xBase-family `.prg` (dBASE III/IV, FoxPro, Clipper style): `IF` / `DO WHILE` / `FOR` / `DO CASE`, `PROCEDURE` / `FUNCTION` / `RETURN` / `DO ... WITH`, plus a set of string and numeric builtins.

It is «bold»case-insensitive«/», and any name that is not defined is emitted as a library `CALL`, so `ui_*` / `tty_*` / `dbf_*` can be written directly.

## How to run it on your phone

```
vml run examples/dbase/fizzbuzz.prg
```

Compiling takes a while (one to two minutes for C, a few seconds for scripting languages).
Once the program is running, **the gamepad is at the bottom of the screen** - the D-pad
and the four action buttons are all there. Tap the back arrow in the top-right corner to
return to the Shell.

## What to know before you write

- Output goes to `?` (with a newline) and `??` (without)
- `ui_*` / `tty_*` / `dbf_*` are written «bold»directly«/» (an undefined name is always compiled to `CALL <original name>` for the linker to resolve)
- Concatenate strings with `+`; turn a number into a string with `STR()`
- Comments: a whole line with `*` (at the start of the line), inline with `&&`
- Read and write DBF data files with the existing `dbf_*` library functions (`dbf_open` / `dbf_records` / `dbf_close`)

## Examples

| File | What it shows |
|---|---|
| `fizzbuzz.prg` | FizzBuzz (`FOR` plus `MOD` plus `?`) |
| `primes.prg` | The primes from 2 to 40 (`FUNCTION` plus a loop plus a logical return) |
| `strings.prg` | Builtin string functions plus calling a procedure with `DO ... WITH` |

## Pitfalls we hit on real devices

- ⚠ «bold»`#` is the not-equal operator, so this front end deliberately does not run the C preprocessor«/» - do not expect `#include` to work; `a # b` means "a is not equal to b".
- ⚠ «bold»Types are inferred at compile time and the inference is flow-insensitive«/»: when one variable is assigned different types in different branches, «bold»the whole program uses the last of those types«/» - avoid it, or convert explicitly with `INT()`.
- ⚠ There are «bold»no arrays / subscripts«/» (`[` is a «bold»string quote«/»); no date type; no `&var` macro substitution.
- ⚠ Database commands (`USE` / `SELECT` / `INDEX` / `APPEND` / `REPLACE` / `LOCATE` / `SKIP`, ...), the screen layout `@ row,col SAY`, and line input `ACCEPT` / `INPUT` / `WAIT` are all «bold»recognised and skipped whole-line«/» (no error, and no code emitted) - to tell whether a line really took effect, «bold»look for the matching instruction in the compiled output«/».
- Library function names «bold»keep their original spelling«/» (they do not take part in case folding) and must reach the linker verbatim.

---

The rest of this page is taken straight from the VML source (`third_party/vml/VMLPrepares/DBaseCompiler/`):
the `README` covers what this front end supports and how to compile it, and the
language reference covers the syntax itself. When upstream changes, regenerating
this page brings it up to date.

## Language reference

### dBase (xBase) Language Subset Specification

> This describes «bold»the part of the language the dBase front end supports«/» in the
> Dolaima VML platform. It is a subset spec: what is written here is supported and verified.
> Chinese version: `DBASE_LANGUAGE_SPEC.md`.

> «bold»Version«/»: v1.0 | «bold»Date«/»: 2026-10-13 | «bold»Revised by«/»: Shenzhen Tanso Intelligent Technology Co., Ltd.

#### Specification standard

| Field | Value |
|:-----|:----|
| «bold»Target standard«/» | dBase/xBase subset |
| «bold»Publication year«/» | — |
| «bold»Completeness«/» | Subset (not itemised) |
| «bold»Tests«/» | 19 passing / 0 failing / 1 known-red |

#### Keywords

`if` `else` `elseif` `endif` `endi` `do` `while` `enddo` `endd` `for` `to`
`step` `next` `endfor` `case` `otherwise` `endcase` `exit` `loop` `return`
`procedure` `proc` `function` `with` `store` `public` `private` `local`

#### Overview
A subset of dBase/xBase is supported, compiled to VML assembly. dBase/xBase is a «bold»de-facto standard«/» — it has no formal standard number and implementations (dBASE III/IV, FoxPro, Clipper, …) disagree with one another — so this document describes «bold»exactly the part this frontend accepts«/». The frontend is «bold»case-insensitive«/» (the lexer folds to upper case; the «bold»only«/» exception is library function names, which must reach the linker verbatim and so keep their original spelling). It «bold»deliberately does not run the C preprocessor«/» (in dBase `#` is the «bold»not-equal operator«/», so treating `#` as a directive marker would silently change meaning). Database command words (`USE` / `SELECT` / `COUNT` / `TOTAL`, …) are «bold»kept out of the keyword table«/» (they are also very common variable names — `total = 0` would be swallowed as a command), and are instead recognised at statement level by identifier text and «bold»skipped whole-line«/». Any name that is neither a builtin nor user-defined is emitted as `CALL <original name>` for the linker to resolve.

#### Supported language features

The features this frontend accepts are organised by the sections below; each one states what is accepted and what it means:

- «bold»Lexical«/»: comments (`*` at line start, inline `&&`, leading `NOTE`), the case rules, literals (integers / floats / three quoting styles for strings / logical `.T.`), operators and precedence, type promotion — §1
- «bold»Statements«/»: output, assignment, declaration (= registering a variable), conditionals, loops, multi-branch, exit / continue, subprograms — §2
- «bold»Builtin functions«/»: `LEN` / `UPPER` / `LOWER` / `SUBSTR` / `STR` / `VAL` / `INT` / `MOD` / `ABS` / `ROUND` — §3
- «bold»Calling library functions directly«/»: `ui_*` / `tty_*` / `dbf_*` are written as-is and compile to `CALL <original name>` — §4
- «bold»Calling convention«/»: arguments pushed right-to-left, caller cleans the stack, return value in `R0` (Int/Str/Bool) or `D0` (Float) — §5
- «bold»Explicitly not supported«/»: arrays and subscripts, date types, macro substitution `&var`, database command forms, `@ row,col SAY`, line input `ACCEPT` / `INPUT` / `WAIT` — §6

See the sections below for details.

#### 1. Lexical

##### 1.1 Comments
- «bold»Whole-line«/»: `*` at the start of a line (after leading whitespace).
- «bold»Inline«/»: `&&` to end of line.
- `NOTE …` at the start of a line is also a comment.

> A `*` anywhere else is multiplication (`x = 5 * 2`).

##### 1.2 Case
dBase is «bold»case-insensitive«/»: keywords, built-in names, and user variable/procedure names are
folded to upper case. The one exception is «bold»library function names«/» (`ui_2d_clear`, `dbf_open`) —
they keep their original spelling for the linker.

##### 1.3 Literals
| Form | Example | Track |
|:--|:--|:--|
| integer | `42`, `-7` | Int (4 bytes) |
| float | `3.14`, `1.5e3`, `.5` | Float (8-byte double) |
| string | `"abc"`, `'abc'`, `[abc]` | all three quote styles are strings |
| logical | `.T.` / `.F.` (also `.Y.` / `.N.`) | 1 / 0 |

Doubled quotes inside a string mean one literal quote: `"say ""hi"""` → `say "hi"`.

##### 1.4 Operators (lowest to highest precedence)
`OR` < `AND` < comparisons (`= == <> # != < > <= >=`) < `+ -` < `* / %` < `** ^` (right-assoc) < unary `- + .NOT.`.

- `/` is always «bold»real division«/» (`10 / 3` = `3.3333333`); use `INT(a/b)` or `MOD` for integer division.
- `%` is integer modulo.
- `**` / `^` is power (both int → `ipow`; either float → `pow`).

##### 1.5 Type promotion
String on either side of `+` → string concatenation; otherwise Float wins over Int.
Comparisons and logical operators always yield «bold»Bool«/» (0/1).

#### 2. Statements

Statements are newline-terminated (`;` also acts as a newline).

##### 2.1 Output
```
? expr [, expr …]     * print with newline
?? expr [, expr …]    * print without newline (`:` is a synonym)
?
```

##### 2.2 Assignment
```
x = 42
x := 42
STORE 42 TO x
STORE 42 TO a, b, c
m.x = 42
```

##### 2.3 Declarations (variable registration)
`PUBLIC a, b` / `PRIVATE c` / `LOCAL d`

##### 2.4 Condition
```
IF cond
  …
ELSEIF cond
  …
ELSE
  …
ENDIF
```

##### 2.5 Loops
```
DO WHILE cond        * pre-test: the body runs zero times if cond is false
  …
ENDDO

FOR i = start TO end [STEP step]
  …
NEXT
```
- `STEP` defaults to `1`.
- A «bold»negative constant«/» step (`STEP -1`) loops downward (`i >= end`); otherwise upward (`i <= end`).
- A *variable* step cannot have its direction determined (known limitation, KNOWN-D01).

##### 2.6 Multi-branch
```
DO CASE
  CASE cond
    …
  OTHERWISE
    …
ENDCASE
```

##### 2.7 Loop control
`EXIT` breaks the innermost loop; `LOOP` jumps back to its condition.

##### 2.8 Subroutines
```
PROCEDURE name [(p1, …)]
FUNCTION name [(p1, …)]
  …
  RETURN [expr]
```
`FUNCTION` returns a value (0 if none); `PROCEDURE` returns nothing. «bold»Recursion works.«/»
Parameters live on the stack; variables live in the data section (globally visible).

Call: `DO name [WITH a, …]` (statement) or `result = name(a, …)` (expression).

#### 3. Built-in functions

| Function | Returns | Note |
|:--|:--|:--|
| `LEN(s)` | Int | string length (`strlen`) |
| `UPPER(s)` / `LOWER(s)` | Str | case conversion |
| `SUBSTR(s, start [, len])` | Str | «bold»`start` is 1-based«/» |
| `STR(n)` | Str | number → string |
| `VAL(s)` | Int | string → integer |
| `INT(x)` | Int | truncate toward zero |
| `MOD(a, b)` | Int | modulo |
| `ABS(x)` | same | absolute value |
| `ROUND(x [, n])` | same | round to `n` decimals (`n` defaults to 0) |

#### 4. Direct library calls

Any name that is neither a built-in nor user-defined compiles to `CALL <name>`, resolved by the
linker against the shared libraries — `ui_2d_clear(0)`, `tty_puts("x")`, `dbf_open("a.dbf")` all work.
Arguments are passed as 4-byte integers. `Lib/dbase/builtin.vml` already links the print/string/
convert/math/`dbf` modules; add a `.linked` line there for more.

#### 5. Calling convention

Arguments are pushed right-to-left; the callee reads them from `[R12+12+4i]` (or the matching offset
for 8-byte types); the «bold»caller cleans the stack«/». Return value is in `R0` (Int/Str/Bool) or `D0` (Float).

#### 6. Explicitly unsupported (this subset)

- Arrays / subscripts (`[` is a string quote here).
- Date type, macro substitution `&var`.
- DB command forms (`USE` / `SELECT` / `INDEX` / `APPEND` / `REPLACE` / `LOCATE` / `SKIP` / …) —
  recognised and «bold»skipped line by line«/» (no error). Use `dbf_*` functions to read/write DBF.
- Screen layout `@ row,col SAY …` (skipped).
- `ACCEPT` / `INPUT` / `WAIT` (skipped).

## Compiler README

### dBase (xBase) Compiler

«bold»Path«/»: `VMLPrepares/DBaseCompiler/`
«bold»Language key«/»: `dbase` | «bold»Namespace«/»: `DBaseCompiler` | «bold»Source extension«/»: `.prg`
«bold»Language library«/»: `Lib/dbase/` (`builtin.vml` + the declaration file `shared.prg`)
«bold»Status«/»: production-ready subset ("full operators + control flow + function calls"; you can write general programs)

#### In one line

Compiles xBase-family (dBASE III/IV, FoxPro, Clipper style) `.prg` sources into VML:
comments, output, assignment, arithmetic/comparison/logical operators,
`IF` / `DO WHILE` / `FOR` / `DO CASE`, `PROCEDURE` / `FUNCTION` / `RETURN` / `DO … WITH`,
plus a set of string/numeric built-ins.

> «bold»Not to be confused with `dbf`«/»: `scripts/vml-dbf-probe/` and `Lib/shared/dbf.vml` in this
> repository are the «bold»DBF data-file format«/» library/probe, «bold»not«/» a language. This directory is a
> «bold»dBase language front end«/»; the two are unrelated.

#### Features

- Lexer / Parser / CodeGenerator built on `CompilerBase` (`LexerBase` / `ParserBase<>` / `CodeGeneratorBase`)
- Comments: leading-line `*` and inline `&&`
- Output: `?` (newline) and `??` (no newline), multiple expressions separated by commas
- Assignment: `var = e`, `var := e`, `STORE e TO v1, v2 …`
- Declarations: `PUBLIC` / `PRIVATE` / `LOCAL` (treated as variable registration)
- Types: integer (i32), float (f64), string, logical (`.T.`/`.F.`)
- Operators: `+ - * / % «bold»` (`^` = `«/»`), comparisons `= == <> # != < > <= >=`, logic `.AND.`/`.OR.`/`.NOT.`
- Control flow: `IF…ELSEIF…ELSE…ENDIF`, `DO WHILE…ENDDO` («bold»pre-test«/»), `FOR…TO…STEP…NEXT`, `DO CASE…CASE…OTHERWISE…ENDCASE`, `EXIT`/`LOOP`
- Subroutines: `PROCEDURE`/`FUNCTION` (parameters, recursion), `RETURN [expr]`, `DO name [WITH args…]`
- Built-ins: `LEN` `UPPER` `LOWER` `SUBSTR` `STR` `VAL` `INT` `MOD` `ABS` `ROUND`
- Direct library calls: any unknown name → `CALL <name>` (`ui_*` / `tty_*` / `dbf_*` … usable directly)
- Case-insensitive keywords/identifiers; library names keep their original spelling for the linker
- Outside the subset: arrays, date type, macro substitution `&var`, and DB command forms (`USE`/`SELECT`/`INDEX` …) — those lines are skipped

#### Usage

```bash
# during development (this project's csproj is an Exe)
dotnet run --project VMLPrepares/DBaseCompiler -- foo.prg -o foo.vml

# via vmlcli (after the integration step)
vmlcli foo.prg --lang dbase
```

#### Type model

dBase is dynamically typed; this front end does a «bold»flow-insensitive static approximation«/»:

| Track | Width | Register | What falls here |
|:--|:--|:--|:--|
| Int / Bool / Str | 4 bytes | `R0` | integers, logicals, string pointers |
| Float | 8 bytes (double) | `D0` | numbers with a decimal point / exponent |

Variables live in the «bold»data section«/» (`var_<NAME>`); only «bold»subroutine parameters«/» use the
stack (`[R12+12+off]`, the same `__stdcall` argument area the shared libraries use).

#### Relation to the `dbf` library

DBF read/write is the existing library's job and is «bold»not«/» reimplemented here.
`Lib/dbase/builtin.vml` already links `../shared/dbf.vml`, so you can call `dbf_open(...)`,
`dbf_records(h)`, `dbf_close(h)` directly as ordinary library functions.

#### Probe

```bash
scripts/vml-dbase-probe/run.sh          # 19 pass / 0 fail / 1 known-red  (via vmlcli --lang dbase)
```

Both stages go through «bold»`vmlcli` (the real channel)«/»: (1) `vmlcli <case.prg> --lang dbase --vml <tmp>.vml`
(compile + assemble + link), (2) `vmlcli <tmp>.vml` (load + run). Do «bold»not«/» use the bundled
`scripts/vml-dbase-probe/runner/` as the criterion — it assembles its own link set, which hides defects
like a missing `Lib/dbase/` module set (that is exactly what it missed on first integration).

> ⚠ `Lib/dbase/` needs its own module set
> (`dotnet run --project third_party/vml/tools/GenLib -- -m -l dbase -r third_party/vml`).
> Without it, bare `.linked` names in the product header (`console.vml` …) resolve to **another
> language's** modules and linking fails with a string of `printx_int32` undefined errors.

#### See also

- Language spec: `DBASE_LANGUAGE_SPEC.en.md`
- Integration checklist: `INTEGRATION.md`
- Defect ledger: `bugs/vml_dbase_bugs/DBASE问题清单.md`
