![如何对带有标签的后缀变量的 vardef 声明进行参数化?](https://linux22.com/image/329844/%E5%A6%82%E4%BD%95%E5%AF%B9%E5%B8%A6%E6%9C%89%E6%A0%87%E7%AD%BE%E7%9A%84%E5%90%8E%E7%BC%80%E5%8F%98%E9%87%8F%E7%9A%84%20vardef%20%E5%A3%B0%E6%98%8E%E8%BF%9B%E8%A1%8C%E5%8F%82%E6%95%B0%E5%8C%96%EF%BC%9F.png)
在 metapost 中,我尝试定义一个宏,为各种相关属性提供声明。
我有一个“对象”(本例中为 xyz),用变量上的后缀来表示,还有该对象的几个属性,用该后缀上的标签来表示.a
,,,.b
等等.c
。
我的目标是让我的宏声明这些变量,而不是由调用者声明它们。
我有:
vardef S@#(expr p) =
pair s@#.a;
pair s@#.b;
pair s@#.c;
s@#.c := p;
draw s@#.c withpen pencircle scaled 6bp withcolor blue;
enddef;
beginfig(1)
S.abc(origin);
S.xyz(origin);
endfig;
end.
abc
这对于命名我的“对象”和来说很好xyz
,但我希望它们以数字形式命名,就好像它们是一个数组一样,这样我可以写:
S0(origin);
S1(origin);
我不明白为什么这是一个错误,因为据我所知它应该产生一个变量s0.c
。但是:
! Illegal suffix of declared variable will be flushed.
<to be read again>
1
S->begingroup.pair.s(SUFFIX2)
c;
是否有可能做到这一点?
我不会介意稍微改变一下语法,比如n(S0, origin)
如果有必要的话。但我正尝试利用 Metapost 的后缀(无论是显式的还是隐式的)与标签结合。
谢谢
答案1
问题是你不能在声明中有明确的下标。
当@#
扩展为数字标记(例如)时0
,您的宏会尝试声明pair s0a;
哪个会触发您看到的错误。
Metapost 语法规则仅允许在类型声明中使用“集体”下标。这些下标由空括号表示[]
,因此,如果要使用数字作为对象,则必须将声明更改为:
pair s[]a;
pair s[]b;
pair s[]c;
但这将仅有的处理数字,这样你就可以拥有
S0(origin);
但不是
S.abc(origin); % <-- won't work
背景介绍
回顾一下有关 token 的规则可能会有所帮助。Metapost 遵循 Knuth 的 Metafont Book 第 6 章中规定的标记化规则。有三种类型的 token:
- 数字标记,例如
3.14
,42
,.866
- 字符串标记,例如
"phvr8r"
以"
- 象征性标记(其他一切)。
然后将符号标记分为“火花”和“标签”:“火花”是对 MP 有意义的符号标记(原始命令的名称或定义的宏的名称);每个其他符号标记都是一个标签。
当您声明一个新变量时,它的名称必须以标签开头。
这条规则听起来很晦涩,但它只是意味着变量名不能以字符串开头,或以数字标记开头,或以已经用于宏或原始命令的名称开头。这对于编程语言来说很正常。
MP 中变量名的棘手之处在于,您还可以在名称中添加一个称为“后缀”的东西。有效后缀的规则是
- 空的
- 或有效后缀后跟标签
- 或者一个有效的后缀,后跟一个称为“下标”的东西,它是一个简单的数字标记,或者是一个用括号括起来的数值表达式。
这意味着你可以使用像p.a
或s12
或k43left
,t[42]
或 这样的变量名f[i+1]
。带括号的变量名看起来很像数组,但实际上并非如此。
唯一的限制是带下标的变量必须具有相同的类型。这是由上述规则强制执行的,该规则禁止在类型声明中使用显式下标,但允许使用“集体”下标。
可能的解决方案
如果您想要找到一种完全通用的方式来声明相关属性,那么您可以重用generic_declare
标准boxes.mp
文件中的例程,该文件将位于您的本地 texmf 树中。