Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

Linux Fu:超越代码的预处理

Posted on 2023-12-29

如果您瞥了一眼标题并想:“我不在乎——我不写 C 代码”,那么请稍等。虽然 C 确实有一个预处理器,而且众所周知,你可以用它做奇怪的事情,并且根据你的观点,可怕或美妙的事情,但实际上还有其他选项,你不必将它们与 C 一起使用程序。实际上,您可以将 C 预处理器用于几乎任何类型的文本文件。而且它并不是唯一可以以这种方式滥用的预处理器。例如,m4 预处理器非常复杂,大大未得到充分利用,并且可以处理 C 源代码或您想要发送给它的任何其他内容。

定义

我将预处理器定义为一个程序,它将其输入文件转换为输出文件,对可能嵌入在文件本身中的命令做出反应。大多数情况下,该输出会被发送到其他程序来完成“真正的”工作。这涵盖了 C 预处理器cpp 。它还涵盖了sed等内容。老实说,您可以使用 C、 awk 、Python、Perl 或任何其他编程语言轻松创建自定义预处理器。您可以将许多其他标准程序视为预处理器,例如tr 。然而,最强大的功能之一是预处理复杂的输入文件,称为 m4。由于某种原因——也许是因为它的复杂性——你在野外看不到太多 m4。

什么预处理器?

如果您只使用过现代 C 编译器,您可能想知道预处理器在哪里。据您所知,普通系统现在只需一次即可完成整个编译。但是,如果您愿意,您的编译器应该提供一个cpp可执行文件,在外部执行预处理器逻辑。对于 gcc (以及许多其他编译器),预处理器被命名为 — 毫不奇怪 — cpp 。预处理器有四个主要任务:

  1. 将一个字符串替换为另一个字符串,包括看起来像函数调用的“宏”。
  2. 评估表达式并根据表达式的值包含部分输入或排除它们。
  3. 删除评论。
  4. 读入其他文件。

当然,通常情况下,输入是 C 源代码,输出则发送给编译器,但不一定是这样。

一个简单的例子

假设您有某种配置文件,其中包含最初为英文的消息。该文件如下所示:

消息1:早上好 消息2:晚安 message3:猫是白色的

我们希望对其进行安排,以便我们可以轻松更改消息并构建新的配置文件。有多种方法可以做到这一点,每种方法都有一些优点和缺点。

假设您有一个名为langs的文件:

 #定义英语0 #define 西班牙语 1

显然,您可以在此处添加更多语言,并且数字是任意的,只要它们是唯一的即可。

现在,我们可以为最终的配置文件创建一个模板:

 #include“语言”  #ifndef 朗格 #define LANG 英语 #万一  #包括“xlat”  消息 1:GOOD_MORNING 消息2:晚安 消息3:猫(白色)

关于此文件有几点需要注意。首先,它包括我们的语言定义文件。然后它将LANG定义为这些符号之一,除非其他东西已经定义了它。我们很快就会看到这可能是什么,但假设现在将LANG设置为ENGLISH 。

xlat的包含会使用我们选择的任何语言的正确字符串填充诸如GOODMORNING之类的标签。 xlat样子如下:

 #如果语言==英语 #define WHITE 白色 #define GOOD_MORNING 早上好 #define GOOD_NIGHT 早上好 #define CAT(clr) 猫是 clr  #万一  #if LANG==西班牙语 #define 白色白色 #define GOOD_MORNING 布宜诺斯艾利斯 #define GOOD_NIGHT 布埃纳斯诺奇斯 #define CAT(clr) El gato es clr #万一

请注意,早上好消息中包含 Unicode 字符。这是使用此类工具的一个小问题。编码将以C 风格转义字符的形式出现。根据您要使用输出的用途,这可能是可接受的,也可能是不可接受的。事实上,预处理器为编译器做了一些我们可能想要抑制的事情。

如果你只是运行:

 .cpp模板

你得到:

 # 0“模板”  # 0 “<内置>”  # 0 "<命令行>"  # 1 “/usr/include/stdc-predef.h” 1 3 4  # 0 "<命令行>" 2  #1“模板”  #1“语言”1  #2“模板”2    #1“xlat”1  #8“模板”2   消息1:早上好  消息2:晚安  message3:猫是白色的

我们想要的是在底部,确实如此,但是有很多东西可以帮助编译器生成错误消息和其他东西。

诀窍是在命令行上添加一些选项:

 cpp -udef -P 模板

这些选项适用于 gcc 的预处理器。如果您使用其他东西,您可能必须做出自己的决定。

定制

如果您想要西班牙语版本,您只需编辑该文件即可。但您也可以告诉预处理器强制使用 LANG 符号,并且由于模板不会重新定义它,因此您将获得您选择的语言:

 cpp -udef -P -D LANG=西班牙语模板

正如我提到的,在此之后 Unicode 字符会看起来很有趣,具体取决于您如何看待它。

其他方式

这不是本示例中使用预处理器的唯一方法。您可以检测语言,然后包含不同的文件(英语或西班牙语)以获得相同的结果。例如,这将具有许多小的独立文件的优点,您可以将其发送给不同的翻译人员。

可能还有许多其他方法可以做到这一点。预处理器就像一个多功能工具。几乎任何事情都有很多方法可以做。

类固醇预处理器

如果您真的想熟悉预处理器,请尝试m4 。它在思想上与 C 预处理器类似,但具有许多超能力。它不是 C 所特有的,因此您不需要做太多事情就可以让它处理您的文件。与 C 预处理器不同, m4不关心行。例如,考虑以下输入:

你好! 定义(HACKADAY,1) 测试我们的宏: 黑客日 结束

如果您通过m4运行它,您会注意到 Hello 和“Testing”行之间有一个奇怪的空行。为什么?因为宏定义只消耗到右括号为止的字符。其他所有内容仍然在文件中,包括末尾的换行符。如果您在定义后输入一些文本,那么没有问题,它将显示在输出中。

如果您想忽略该行的其余部分,可以使用dnl (删除到新行),如下所示:

定义(HACKADAY,1)dnl

m4 中的参数使用美元符号表示法,与 shell 非常相似。引用也很奇怪,因为您使用反引号来打开并使用撇号来关闭。像这样:

定义(HACKADAY,`eval(10**$1)')

正如您所料,这允许您输入 HACKADAY(2) 并得到 100 作为结果 — 双星号表示求幂。

愉快的消遣

m4的最佳功能之一是它具有至少十种不同的输出流。默认为流 0,其余的编号为 1 到 9。您可以轻松写入任何流,或写入超出范围的流(如 -1)以丢弃输入。最后,输出流按顺序放在一起。例如,假设您可以有一个宏来将项目添加到报表中。该报告有标题、正文和总计列。您可以将所有标头代码放入第一个流(或 m4 所说的“转移”)中。然后将主体代码放入转移2,将总代码放入转移3。

最后,生成的程序将包含所有标题,然后是所有正文项,最后是总计,您可以按照您认为方便的任何顺序编写它们。如果您想丢弃文本,则应转向负文件号。一些m4程序(包括 GNU 程序)允许比标准数量更多的转移。

作为一个简单的示例,请考虑以下脚本:

 dnl 这些评论将被丢弃 dnl 首先,我们要转向#1 dnl 然后我们将打印每个单词以及计数 dnl 递增计数 (_c) dnl 最后,我们将切换回 0 并输出计数 dnl 这样,“报告”的标题就会有计数 dnl 后跟我们想要计数的单词 转移(1)dnl 定义(_c,0)dnl 定义(WC,` 定义(`_c',incr(_c))dnl _c: $1')dnl 厕所(你好) 厕所(那里) WC(黑客日) 世界杯(2024) 转移(0)dnl _c 单词列表:

请注意,以dnl开头的行本质上是注释。其余的内容很神秘,但其想法是定义一个宏来输出带有序列号的单词列表。标头包含总计数,当然,直到最后我们才知道。但由于标头放置在转移 0 中,其余部分放置在转移 1 中,因此一切都按正确的顺序出现。

关于m4内容太多,无法在一篇文章中涵盖,但您可以自己阅读更多相关内容。老实说,如果您确实需要m4的强大功能,也许您应该考虑 awk 或 Python。不过,您可能必须重新创建自己版本的转移系统,因此如果您确实需要该功能,也许m4可以提供一些东西。

另一方面,也许尝试awk 。或者以糟糕的方式混合 awk、shell 脚本和 C 处理器。

原文: https://hackaday.com/2023/12/28/linux-fu-preprocessing-beyond-code/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Rohit Patel
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme