← 都来码 / Dolaima← 例程索引basic/test/libs.bas原文

basic/test/libs.bas · 5017 字节 · 下载原文

' 共享库一览 —— 用 **BASIC** 把四个共享库各叫一遍
' Shared libraries tour -- calling all four shared libraries from **BASIC**
'
' ◆ 这份例程在练什么
' ◆ What this example exercises
'
' 共享库是**一次投入、22 门语言都受益**的那种东西:`regex`(正则)· `dbf`(dBASE 数据文件)
' · `sql`(跑在 .dbf 上的查询)· `turtle`(海龟作图)。它们**不是 BASIC 的库**,
' 而是每一门语言都能调的同一份实现 —— 这份例程就是"从 BASIC 这边调得动"的活证据。
' The shared libraries are one investment serving all 22 languages: `regex`, `dbf` (dBASE data
' files), `sql` (queries over .dbf) and `turtle`. They are not BASIC libraries -- they are one
' implementation every language can call. This example is the living proof that BASIC can.
'
'   regex  : 模式 `abc` 在 `xxabcyy` 里**找得到**吗(1 = 找得到)
'   dbf    : 现建一张两字段的表、塞两条记录,再看一眼记录数
'   sql    : 在刚建的那张表上跑一句 `SELECT ... WHERE`
'   turtle : 抬笔走 50 步,看它的坐标(不写屏幕,所以**不需要开窗口**)
'
' ◆ 为什么全程只调"返回整数"的那些接口
' ◆ Why only the integer-returning calls
'
' BASIC 的字符串**不可变** ⇒ 传不出一个可写缓冲区,而 `dbf_get` / `sql_cell` 这类要调用方
' 给 dst。所以这里走另一条路:**需要缓冲区的地方用 `alloc()` 自己拿一块地址**
' (见下面建记录那两句),取值一律用"只问长度"的形态(`dbf_fname(h, 0, 0)`)。
' BASIC strings are immutable, so there is no writable buffer to hand to `dbf_get`/`sql_cell`.
' Two ways around it: take an address yourself with `alloc()` (see the record-building lines),
' and use the "length only" form of the accessors (`dbf_fname(h, 0, 0)`).
'
' ◆ 本前端的两条写法要求(实测)
' ◆ Two syntax requirements of this frontend (measured)
'
'   ① 库函数**不需要**任何声明文件 —— 直接调就行(四库各判一条,见文件末尾的 EXPECT 行)。
'   1. Library functions need **no** declaration file -- just call them (each of the four
'      libraries has its verdict pinned in the EXPECT line at the end of this file).
'   ② 模块级变量必须在赋值前 `DIM`(这是 BASIC 本来的规矩,与共享库无关)。
'   2. Module-level variables must be `DIM`ed before they are assigned (a plain BASIC rule,
'      unrelated to the shared libraries).
'
' ◆ 一处写法上的取舍
' ◆ One deliberate choice
'
' 字段类型用的是**字符的字节值**('C' = 67 / 'N' = 78)而不是字符字面量 ——
' 共享库那几个接口收的就是这个整数(C 的 `char`),写成数字**任何一门语言都读得懂**。
' Field types are given as the **byte value of the character** ('C' = 67 / 'N' = 78) rather than
' a character literal: that is what the library entry points take (C's `char`), and writing it as
' a number reads the same in every one of the 22 languages.
'
' ⚠ 跑一次会在**本文件所在目录**建一个 `libdemo.dbf`(这就是 dbf 那一半在演示的事)。
' ⚠ Running this creates a small `libdemo.dbf` **next to this file** -- that is the point of it.

' ── 变量声明(必须在赋值之前)──
DIM h AS INTEGER
DIM rec AS INTEGER

' ── regex:模式匹配 ──
PRINT "REGEX_HIT="; re_test("abc", "xxabcyy")
PRINT "REGEX_MISS="; re_test("abc", "xxabxyy")
PRINT "REGEX_VALID="; re_is_valid("(a|b)+")

' ── dbf:建表 → 塞两条 → 读记录数 ──
h = dbf_new("libdemo.dbf")
dbf_addfield(h, "NAME", 67, 8, 0)
dbf_addfield(h, "AGE", 78, 3, 0)
dbf_build(h)

rec = alloc(64)
dbf_mkrec(h, rec)
dbf_put(h, rec, 0, "Alice")
dbf_put(h, rec, 1, "30")
dbf_add(h, rec)
dbf_mkrec(h, rec)
dbf_put(h, rec, 0, "Bob")
dbf_put(h, rec, 1, "7")
dbf_add(h, rec)
dbf_flush(h)

PRINT "DBF_ROWS="; dbf_records(h)
PRINT "DBF_FIELDS="; dbf_fields(h)
PRINT "DBF_FIELD0_LEN="; dbf_fname(h, 0, 0)
dbf_close(h)

' ── sql:在刚建的表上查 ──
PRINT "SQL_ROWS="; sql_run("libdemo.dbf", "SELECT * FROM t WHERE AGE > 20")
PRINT "SQL_COLS="; sql_cols()
PRINT "SQL_COL0_LEN="; sql_colname(0, 0)

' ── turtle:抬笔走 50 步(落笔会去画屏幕,那要窗口)──
turtle_reset()
turtle_pen_up()
turtle_forward(50)
PRINT "TURTLE_X="; turtle_x()
PRINT "TURTLE_Y="; turtle_y()

' ── sed:sed 的替换规则(s / y 两条命令,依附 regex 库)—— 缓冲区那一半只有 C 拿得到,
'    这里压的是「只问长度」那一支(cap 传 0)与对账用的 sed_count。
PRINT "SED_COUNT="; sed_count("s/a/X/g", "banana")
PRINT "SED_LEN="; sed_sub("s/a/X/g", "banana", 0, 0)
PRINT "DONE="; 1

' 期望(scripts/lib-examples-check.sh 按这一行比对):
' EXPECT: REGEX_HIT=1|REGEX_MISS=0|REGEX_VALID=1|DBF_ROWS=2|DBF_FIELDS=2|DBF_FIELD0_LEN=4|SQL_ROWS=1|SQL_COLS=2|SQL_COL0_LEN=4|TURTLE_X=0|TURTLE_Y=50|SED_COUNT=3|SED_LEN=6|DONE=1