ladder/test/libs.ld · 6362 字节 · 下载原文
(* 共享库一览 —— 用 **Ladder** 把四个共享库各叫一遍
Shared libraries tour -- calling all four shared libraries from **Ladder**
◆ 这份例程在练什么
◆ What this example exercises
共享库是**一次投入、22 门语言都受益**的那种东西:regex(正则)· dbf(dBASE 数据文件)
· sql(跑在 .dbf 上的查询)· turtle(海龟作图)。它们**不是 Ladder 的库**,
而是每一门语言都能调的同一份实现 —— 这份例程就是"从 Ladder 这边调得动"的活证据。
The shared libraries are one investment serving all 22 languages: regex, dbf (dBASE data
files), sql (queries over .dbf) and turtle. They are not Ladder libraries -- they are one
implementation every language can call. This example is the living proof that Ladder can.
regex : 模式 abc 在 xxabcyy 里**找得到**吗(1 = 找得到)
dbf : 现建一张两字段的表、塞两条记录,再看一眼记录数
sql : 在刚建的那张表上跑一句 SELECT ... WHERE
turtle : 抬笔走 50 步,看它的坐标(不写屏幕,所以**不需要开窗口**)
◆ ⚠ 更正一条旧记录
◆ (!) One stale note, corrected
本目录的 sysinfo.ld 写着「Ladder 没有字符串实参的函数调用」。**那条已经过时** ——
实测 Ladder 现在能正常传字符串实参(本文件第一行判据 re_test("abc","xxabcyy") 就是两个
字符串实参,回 1),也能把调用写在语句位与表达式位两处。
The sysinfo.ld in this directory says "Ladder has no string-argument function calls". That is
**out of date**: measured, Ladder passes string arguments correctly (the very first probe in this
file, re_test("abc","xxabcyy"), takes two string arguments and returns 1), and calls work in
both statement and expression position.
◆ 本前端的写法要求(与 demo_std.ld 同一套)
◆ This frontend's writing requirements (the same set as demo_std.ld)
① 骨架 PROGRAM / VAR ... END_VAR / BEGIN ... END_PROGRAM,语句以分号结尾,
1. Skeleton PROGRAM / VAR ... END_VAR / BEGIN ... END_PROGRAM, statements end with a semicolon,
注释用圆括号加星号那一对;变量**必须**在 VAR 段声明。
comments use the paren-star pair; variables **must** be declared in the VAR section.
② **标签会吃掉它后面的语句** ⇒ 本文件写成直线代码,一个标签都没有。
2. A **label swallows the statement that follows it** => this file is straight-line code with
no label at all.
③ 常量没有声明处,一律写成字面量 —— 所以字段类型直接写 67 与 78
('C' = 67 字符型 · 'N' = 78 数字型),不写字符字面量。
3. There is nowhere to declare a constant, so constants are written as literals -- hence the
field types are the numbers 67 and 78 ('C' = 67 character, 'N' = 78 numeric) rather than
character literals.
◆ 为什么全程只调"返回整数"的那些接口
◆ Why only the integer-returning calls
Ladder 的字符串字面量**取不到可写地址**,而 dbf_get / sql_cell 这类要调用方给 dst。
所以这里走另一条路:**要缓冲区的地方用 alloc 自己拿一块**(见下面 REC 那两行),
取值一律用"只问长度"的形态(dbf_fname(H, 0, 0))。
Ladder string literals give no writable address, and dbf_get / sql_cell need a caller-supplied
dst. So: take a buffer yourself with alloc (see the REC lines below), and use the
"length only" form of the accessors (dbf_fname(H, 0, 0)).
⚠ 跑一次会在**本文件所在目录**建一个 libdemo.dbf(这就是 dbf 那一半在演示的事)。
⚠ Running this creates a small libdemo.dbf **next to this file** -- that is the point of it.
*)
PROGRAM Libs
VAR
H : INT;
REC : INT;
END_VAR
BEGIN
(* ── regex:模式匹配 ── *)
PRINT_STR "REGEX_HIT=";
PRINT_INT re_test("abc", "xxabcyy");
PRINT_CHAR 10;
PRINT_STR "REGEX_MISS=";
PRINT_INT re_test("abc", "xxabxyy");
PRINT_CHAR 10;
PRINT_STR "REGEX_VALID=";
PRINT_INT re_is_valid("(a|b)+");
PRINT_CHAR 10;
(* ── dbf:建表 → 塞两条 → 读记录数 ──
字段类型写**字符的字节值**:'C' = 67(字符型)· 'N' = 78(数字型)。
Field types are the **byte value of the character**: 'C' = 67, 'N' = 78. *)
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_STR "DBF_ROWS=";
PRINT_INT dbf_records(H);
PRINT_CHAR 10;
PRINT_STR "DBF_FIELDS=";
PRINT_INT dbf_fields(H);
PRINT_CHAR 10;
PRINT_STR "DBF_FIELD0_LEN=";
PRINT_INT dbf_fname(H, 0, 0);
PRINT_CHAR 10;
dbf_close(H);
(* ── sql:在刚建的表上查 ── *)
PRINT_STR "SQL_ROWS=";
PRINT_INT sql_run("libdemo.dbf", "SELECT * FROM t WHERE AGE > 20");
PRINT_CHAR 10;
PRINT_STR "SQL_COLS=";
PRINT_INT sql_cols();
PRINT_CHAR 10;
PRINT_STR "SQL_COL0_LEN=";
PRINT_INT sql_colname(0, 0);
PRINT_CHAR 10;
(* ── turtle:抬笔走 50 步(落笔会去画屏幕,那要窗口)── *)
turtle_reset();
turtle_pen_up();
turtle_forward(50);
PRINT_STR "TURTLE_X=";
PRINT_INT turtle_x();
PRINT_CHAR 10;
PRINT_STR "TURTLE_Y=";
PRINT_INT turtle_y();
PRINT_CHAR 10;
(* ── sed:sed 的替换规则(s / y 两条命令,依附 regex 库)—— 缓冲区那一半只有 C 拿得到,
这里压的是「只问长度」那一支(cap 传 0)与对账用的 sed_count。
*)
PRINT_STR "SED_COUNT=";
PRINT_INT sed_count("s/a/X/g", "banana");
PRINT_CHAR 10;
PRINT_STR "SED_LEN=";
PRINT_INT sed_sub("s/a/X/g", "banana", 0, 0);
PRINT_CHAR 10;
PRINT_STR "DONE=";
PRINT_INT 1;
PRINT_CHAR 10;
END_PROGRAM
(* 期望(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
*)