Skip to content

Minep/PonyText

Repository files navigation

PonyText

0. 这是什么?

PonyText是一个非“所见即所得”的文本排版工具(如MS Word),是一个简易的文本排版以及预处理系统。用户将通过编写纯文本文件,从而获得排版后的文本。

1. 为什么会有这东西?

关于这个问题,这东西其实是在我写小说时想到的。写过小说的都知道,人物/地点/物体的名称并不是很好起,有时因为想起个好名字,从而导致陷入一个一筹莫展的死循环中——名字想不到,剧情无法进展。

不过最终,你还是会起了一个名字,并且在后续的情节推动中使用了这个名字。

这确实很美好,但是有一天,因为某些原因你想要去更改这个名字(可能是后来发现这个名字不是很妥当,比如,你想到了一个更好的名字,或者原来的名字蕴含了种族歧视,导致你的部分读者不高兴了)。但是你发现,你的情节已经推动到了不知道什么地方去了,通过查找发现这个名字在文档中出现了上百次。

当然了,你可以直接全局替换。这在大部分场合是可以的,但是有些情况可能并不允许。现在我们来看个例子:

假设你有一个角色,叫做 “星光”,你的文本中有这两句话:

他站在满天的星辰之下,似乎在思考着什么。星光照耀着他的面庞,照出了他脸上的沧桑。

以及

星光兴高采烈的说道:……

这个时候,一般是你写小说的某个时候,你发现“星光”这个名字可能有些模棱两可(ambiguous),于是你想到了一个更好地名字:“星光熠熠”。于是你进行全局替换,你会得到:

他站在满天的星辰之下,似乎在思考着什么。星光熠熠照耀着他的面庞,照出了他脸上的沧桑。

以及

星光熠熠兴高采烈的说道:……

当然,第二句是没有问题,我们能立刻反映出来“星光熠熠”是个人物。但是第一句就有点问题了。这给人的反应是:星光熠熠这个角色拿着某种光源,在照射着那个人的脸庞。于是在上下文中,这意思立刻就改变了。

出于这个原因,我就编写了PonyText,通过引入“宏处理”来解决这一问题,顺带做了排版功能。同时,PonyText也算是我对编译原理这门课的一个实践和理解。

2. 这东西可以做什么?

在目前的版本中,PonyText可以……

  • 宏处理
  • 基本的排版(对齐,加粗,字号,字体等……)
  • 文本结构化(这样你就可以方便的使用Git来版本控制了)

3. 和LaTeX有点像,这是重复造轮子吗?

我承认,这有些“重复造轮子”。你可以看到,我用了“有些”,而不是“确实”。虽然PonyText和LaTeX功能基本一样,甚至在某些方面不如LaTeX(PonyText无法渲染数学文本,而且PonyText不是图灵完备的)。但这也并不碍事,毕竟PonyText的初衷只是实现简单的文本预处理。

当然了,对比LaTex,PonyText的语法是简洁易懂的,学习曲线并没有LaTeX那么陡峭(i.e. 门槛稍低)。并且和LaTeX一样,支持对指令的拓展。

4. PonyText快速上手

和编程语言不一样,PonyText只是一个文字排版语言。这就意味着PonyText主要以正常的文字、段落为主。和LaTeX一样,PonyText通过调用一系列的命令(在PonyText里叫做预处理器)来执行一些对文本的操作。

4.1 段落

和LaTeX一样,PonyText使用了正常的段落标识——换行表示另起一段。为了方便展示,我们用\n表示一个换行操作(按一下回车键):

文学程序是用自然语言(比如英语)写出来的对程序逻辑的解释,程序中交织点缀着宏和传统源代码段。在文学编程的源文件中,宏很简单,它或与标题类似,或是解决编程问题时用人类语言描述抽象的解释性短语。它把代码段或更低层次的宏隐藏了起来,且与计算机科学教学时经常用到的,用伪代码写的算法相似。\n 这些任意解释的短语成为新的精确的操作符,操作符由程序员在运行过程中创建,组成了在基本编程语言之上的“元语言”。 预处理器用于替换任意层级,说得更准确些是“在'网'和宏之间创建联系”。

4.2 如何使用预处理器?

一个预处理器的调用看上去是这个样子的:

@define MACRO "这是一个字符串。"

我们可以看出,符号@后面(就是我们电子邮箱地址中的那个符号!),紧跟着的是你需要使用的预处理的名称。而之后则是这个预处理器将会接受到的参数,每个参数之间以空格作为分隔。

当然了,参数有不同的类型,这点我们会在后面看到。

4.3 我们在哪里调用这些预处理器?

PonyText使用 \${.....} 来标记一个调用可能会出现的地方,如:

\${@define MACRO "这是一个字符串。"}

这个意思就是说,我们调用了一个名字叫做define的预处理器,并传进了两个参数。

注意,这里我把 “一个” 特地加粗了一下,这是因为\${.....}只能放置一个调用。当然,你也可以把多个调用写道一起,利用\$ .... \$进行标记多个调用。

\$
@define MACRO "字符串1"
@define MACRO2 "字符串2"
@maintitle "文档标题"
\$

有过编程经验的读者可以看出,每个语句(调用)之间没有冒号分隔。这就意味着换行符在PonyText里有特殊的含义。不管是段落也好,还是调用也好,都是通过换行符分割的。

注意: 为了保证可读性,在标记多行调用时,开头的\$后面,以及结尾的\$前面,都必须要放置一个换行符。这也就是说:

\$ @define MACRO "字符串1"
@define MACRO2 "字符串2"
@maintitle "文档标题"
\$

\$
@define MACRO "字符串1"
@define MACRO2 "字符串2"
@maintitle "文档标题"\$

都是非法的。

4.4 使用宏

我们其实已经可以看到定义宏的命令是

@define 宏名称 宏的值

如果说我们现在有一个叫做MACRO1的宏变量,我们可以通过这个方法去使用他:

\${MACRO1}

这个其实是\${@echo MACRO1}的简写。

声明宏的时候,不用担心保留字问题,因为PonyText没有保留字!哪怕是命令的名称也没问题,比如你可以这么干:\${@define define "define"}。这一点问题都没有!不过为了可读性,建议不要这么做。

4.5

4.6 全部整合起来

那么我们在开头给的例子可以写成:

\$
@define STARLIGHT "星光熠熠"
\$
他站在满天的星辰之下,似乎在思考着什么。星光照耀着他的面庞,照出了他脸上的沧桑。

\${STARLIGHT}兴高采烈的说道:……

一切都十分完美,这样一来,当我们再想改名字时,我们只需要修改对应的宏变量的值就可以了。

不过还有一点需要注意一下,虽然并不是很致命,但是我觉得还是值得说明一下。我们注意到上面的最后一行:

\${STARLIGHT}兴高采烈的说道:……

这和

\${STARLIGHT}
兴高采烈的说道:……

不是一回事。虽然\${STARLIGHT}在预处理阶段都会被替换成我们定义的“星光熠熠”。但是在第二个示范中,我们的\${STARLIGHT}后面跟了个回车(换行符),根据我们之前说过的 “PonyText段落的定义”,我们立刻可以发现这样的\${STARLIGHT},会被PonyText识别为一个单独的段落,所以最后渲染出来是:

星光熠熠
兴高采烈的说道:……

而不是

星光熠熠兴高采烈的说道:……

4.7 再论调用

在前面,我们只是说明了一个调用长什么样子的,但是没有给出正式的定义。正式地讲,一个调用是这个样子的:

@<name> [<arg><space>+]*

这是什么意思?学过编译原理的可能一下就看出来了。<name>是一个表示符,也就是一个只有26个英文字母大小写以及下划线的字符串,如Ae2_ss__Hyhj_2是合法的,而形如3Hz_以及#Hz2是不合法的,这和几乎绝大多数编程语言的变量名/函数名定义是一样的。 后面[<arg><space>+]*表示可以跟随零个或多个参数,在这里,我用<space>+来强调每个参数之间是需要由一个或多个空格来分割的。

4.8 参数类型

说了那么多参数,我们似乎还没有提到PonyText都支持那些类型的参数。在PonyText里面,参数,也就是上面的<arg>,有这几种类型:

  • 字符串
  • 数字
  • 字典
  • 调用
  • 文学结构

字符串和数字可能都很熟悉,前者是任何用冒号围住的字符串,特殊字符需使用\转义,后者就是普通的数字,如-12312.3,都是合法数字,但是+2332.3.32e-2不是合法数字(是的,PonyText不支持科学计数法)。

字典,其实就是键值对,大家肯定也熟悉。在PonyText中,一个合法的字典是这样的:


可以看到,键可以是字符串或者是普通的标识符,值可以使字符串,数字或者普通表示符。对于普通标识符,PonyText会在预处理阶段时查找相应的宏并进行替换。

那么,后面的调用和文学结构又是什么东西? 关于“调用”,其实就是说你可以命令里面嵌套命令。这是通过使用成对的括号:(...)来实现的,如:

@maintitle (@echo MY_TITLE)

PonyText执行到这种嵌套时,会去执行括号里面的命令,将命令返回的结果(如果有的话)作为参数。(当然,如果没有结果的话,那就是一个空参数。虽然PonyText不会报错(现阶段),但这一点意义都没有。)

About

A simple and naïve typesetting system.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published