2023 年 05 月 11 日
上一篇:新蜗牛 · 秘密
下一篇:新蜗牛 · 其他
基于指针(或引用)可以间接访问某个变量。例如,在 C 语言中,
int a = 3;
int *p = &a;
4;
*p = "%d\n", a); /* 结果为 4 */ printf(
MetaPost 这样的宏语言,该如何像 C 语言这样间接访问变量呢?
scantokens 是 MetaPost 原语,可将字符串转化为 Token(记号)。由于 MetaPost 的原语、宏以及变量等对象的名字皆为 Token,故而其字符串变量便可以作为指针使用。例如,以下代码
numeric a; a := 3;
string p; p := "a";
:= 4;
scantokens(p) draw textext(decimal a);
与上文的 C 代码等效。
有了指针,便可以构造表。有了表,便可批量构造或访问一组变量。例如
string a[]; a[0] := "空"; a[1] := "甲"; a[2] := "乙"; a[3] := "丙";
宫(scantokens(a[0]), a[0]);
for i = 1 upto 3:
宫(scantokens(a[i]), a[i]) 位于 scantokens(a[i - 1]) 偏 (东 1.5cm);
endfor
呜呼 甲, 乙, 丙;
上述代码看上去有些繁琐。宏最擅长化解繁琐:
def 表 (suffix a) (text b) =
string a[];
begingroup
numeric i; i := 0;
save i; for j = b:
:= j;
a[i] := i + 1;
i endfor
endgroup
enddef;
基于 表
,上述构造表的代码
string a[]; a[0] := "空"; a[1] := "甲"; a[2] := "乙"; a[3] := "丙";
可简化为
"空", "甲", "乙", "丙"); 表(a,
在遍历一个表时,为了避免使用幻数,需要定义一个宏,用于查询表中元素个数:
vardef 表长 suffix a =
numeric i; i := 0;
save i; forever:
exitif unknown a[i + 1];
:= i + 1;
i endfor
ienddef;
基于 表长
,对表 a
的遍历代码可写为
for i = 1 upto 表长 a:
... ... ...
endfor
在代码中频繁使用 scantokens
,也颇为繁琐,以 名
代之:
def 名 expr a = scantokens(a) enddef;
于是
- 1]) 偏 (东 1.5cm); 宫(scantokens(a[i]), a[i]) 位于 scantokens(a[i
可简写为
- 1]) 偏 (东 1.5cm); 宫(名 a[i], a[i]) 位于 (名 a[i
若为字符串表定义宏 聚
,将表中除第一个字符串之外的其他字符串依序合并为一个字符串,例如将
"空", "甲", "乙", "丙", "丁", "戊"); 表(a,
所构造的表 a
合并为 "甲, 乙, 丙, 丁, 戊"
,则
呜呼 甲, 乙, 丙, 丁, 戊;
便可简写为
呜呼 名(聚 a);
宏 聚
可定义为
vardef 聚 suffix a =
string s; numeric n;
save s, n; := "";
s := 表长 a;
n for i = 1 upto n:
:= (tostring s) & a[i] & ",";
s endfor;
:= s & a[n];
s
senddef;
&
可将两个字符串合并为一个。
基于上述宏,不难定义以下三个宏,用于构造一组对象并横向或纵向放置它们:
def 之乎者也 suffix a =
for i = 0 upto 表长 a: 宫(名 a[i], a[i]); endfor
enddef;
def 横陈 (suffix a) (expr 间距) =
for i = 1 upto 表长 a:
- 1]).卯门 偏 (东 间距));
定位(名 a[i], 名(a[i]).酉门 位于 名(a[i endfor
enddef;
def 纵列 (suffix a) (expr 间距) =
for i = 1 upto 表长 a:
- 1]).午门 偏 (南 间距));
定位(名 a[i], 名(a[i]).子门 位于 名(a[i endfor
enddef;