← Dolaima← Docs indexdBase原文中文

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 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

Examples

FileWhat it shows
fizzbuzz.prgFizzBuzz (FOR plus MOD plus ?)
primes.prgThe primes from 2 to 40 (FUNCTION plus a loop plus a logical return)
strings.prgBuiltin string functions plus calling a procedure with DO ... WITH

Pitfalls we hit on real devices


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 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.

Version: v1.0 | Date: 2026-10-13 | Revised by: Shenzhen Tanso Intelligent Technology Co., Ltd.

Specification standard

FieldValue
Target standarddBase/xBase subset
Publication year—
CompletenessSubset (not itemised)
Tests19 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 de-facto standard — it has no formal standard number and implementations (dBASE III/IV, FoxPro, Clipper, …) disagree with one another — so this document describes exactly the part this frontend accepts. The frontend is case-insensitive (the lexer folds to upper case; the only exception is library function names, which must reach the linker verbatim and so keep their original spelling). It deliberately does not run the C preprocessor (in dBase # is the not-equal operator, so treating # as a directive marker would silently change meaning). Database command words (USE / SELECT / COUNT / TOTAL, …) are 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 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:

See the sections below for details.

1. Lexical

1.1 Comments

A * anywhere else is multiplication (x = 5 * 2).

1.2 Case

dBase is case-insensitive: keywords, built-in names, and user variable/procedure names are folded to upper case. The one exception is library function names (ui_2d_clear, dbf_open) — they keep their original spelling for the linker.

1.3 Literals
FormExampleTrack
integer42, -7Int (4 bytes)
float3.14, 1.5e3, .5Float (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..

1.5 Type promotion

String on either side of + → string concatenation; otherwise Float wins over Int. Comparisons and logical operators always yield 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
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. 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

FunctionReturnsNote
LEN(s)Intstring length (strlen)
UPPER(s) / LOWER(s)Strcase conversion
SUBSTR(s, start [, len])Strstart is 1-based
STR(n)Strnumber → string
VAL(s)Intstring → integer
INT(x)Inttruncate toward zero
MOD(a, b)Intmodulo
ABS(x)sameabsolute value
ROUND(x [, n])sameround 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 caller cleans the stack. Return value is in R0 (Int/Str/Bool) or D0 (Float).

6. Explicitly unsupported (this subset)

Compiler README

dBase (xBase) Compiler

Path: VMLPrepares/DBaseCompiler/ Language key: dbase | Namespace: DBaseCompiler | Source extension: .prg Language library: Lib/dbase/ (builtin.vml + the declaration file shared.prg) 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.

Not to be confused with dbf: scripts/vml-dbf-probe/ and Lib/shared/dbf.vml in this repository are the DBF data-file format library/probe, not a language. This directory is a dBase language front end; the two are unrelated.

Features

Usage

# 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 flow-insensitive static approximation:

TrackWidthRegisterWhat falls here
Int / Bool / Str4 bytesR0integers, logicals, string pointers
Float8 bytes (double)D0numbers with a decimal point / exponent

Variables live in the data section (var_<NAME>); only 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 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

scripts/vml-dbase-probe/run.sh          # 19 pass / 0 fail / 1 known-red  (via vmlcli --lang dbase)

Both stages go through vmlcli (the real channel): (1) vmlcli <case.prg> --lang dbase --vml <tmp>.vml (compile + assemble + link), (2) vmlcli <tmp>.vml (load + run). Do 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