← 都来码 / Dolaima← 例程索引ladder/test/libs.ld原文

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