Richard Markup v3 帮助文档

来自个人维基
跳转至: 导航搜索

Richard Markup是我设计的一门带逻辑和流程控制的文本标记语言。相比v2,Richard Markup v3 彻底抛弃了XML标签语法的遗留,逻辑与文本平起平坐,不再依附于元素。

目录

基本语法

文件的开头是头部信息,记录了文件格式的版本(v3)和程序应该运行的环境(soullc――灵魂实验室控制台):

<?richard-markup v3 for soullc?>

随后是若干个函数定义。实际运行的内容都要写在函数里面,程序启动时会自动调用名为main的函数。一个简单的main函数写成这样:

|def main:
    Hello, world!

main函数一般是一个块状函数,在函数名后用冒号表示内容开始。与Python类似,Richard Markup v3使用缩进来表示代码块。

此外,还有一种行内函数,它不用冒号表示内容开始,而是写在两个`之间,且不能换行,如:

|def an_inline_function `Hello, world!`

函数也可以有参数,后文会讲到。

与Python不同的是,我们的函数内部的内容默认是文本,运行时会直接输出出来,例如:

|def main:
    Hello, world!
    Hello, Roy!
    Hello, Richard!
    Hello, everybody!

以上代码只会输出四行文本;不过,我们可以在文本中嵌入逻辑。逻辑可分为块状逻辑行内逻辑两种:

|def main:
    块状逻辑:
    |print 1+2
    行内逻辑:
    1 + 2 = {print 1+2}

|开头的是块状逻辑,写在{}中的是行内逻辑。行内逻辑是用来在一行文本中间的某个位置添加逻辑的;其他情况下一般使用块状逻辑,它不能和文本写在同一行。print语句用来在逻辑里输出数据。以上代码应输出:

块状逻辑:
3
行内逻辑:
1 + 2 = 3

可以用#来表示注释,在文本、块状逻辑中,乃至函数外面和函数声明的第一行都可以。不同的是,在文本中注释必须独占一行,而其他地方也可以是在一行正常代码的末尾。

# 一条没有用的注释
|def main: # 主函数
    # Part 1
    Lorem ipsum dolor sit amet.
    这个不是注释:#Hashtag
    |print 114514 # 臭块状逻辑

字面量 变量

可以使用数字、布尔值、字符串、列表等字面量,写法与Python一致:

|def main:
    |print 1
    |print 1.25
    |print True
    |print False
    |print None
    |print "Hello, world!"
    |print '"Hello"'
    |print [1, 2, 3]

以上程序输出:

1
1.25
True
False
None
Hello, world!
"Hello"
[1, 2, 3]

仍然与Python类似,我们可以创建变量:

|def main:
    |a = 114514
    |a += 1919810
    |print a

文本字面量

有时我们还需要在逻辑中引用文本。文本和字符串是不同的,因为文本可以设置属性(在soullc中可以设置字体颜色),也可以在里面嵌入逻辑(禁止套娃!)。

与前面讲的函数相同,文本字面量也分块状和行内,块状也用冒号,行内也用两个`表示:

|def main:
    |print:
        Hello, world!
        Hello, Roy!
    |print `Hello.`
    {print `Hi`}
    |print:
        |print:
            |print:
                |print:
                    禁止套娃!

输出:

Hello, world!
Hello, Roy!
Hello.
Hi
禁止套娃!

直到文本被print时,它里面的逻辑才会执行。在这个例子中,文本被直接print出来了,跟直接写没什么区别。一般的用法是把文本赋值给变量,或作为参数传递。

|def main:
    |a = :
        Richard的XP系统是[数据删除]!
    |print a
    |print a
    |print a
    重要的事情说三遍(迫真

注意,在行内逻辑中没有办法添加块状文本;在行内逻辑中尝试print一个块状内容或调用块状函数都会引发错误。

|def main:
    |a = :
        一个块状文本
    {print a}(会出错)

多行块状逻辑

如果列表字面量或形参(调用函数时传入的参数)列表中有块状文本字面量,或是因为其他原因需要换行,可以这样写:

|def main:
    |list = [
        1, 2, 3
        4, 5, 6
        7, 8, 9
    ]

也就是说,每行的最后一个元素后都不写逗号。这样设计是因为块状文本字面量纯粹使用缩进来表示在哪结束,不方便在它后面写逗号:

|def main:
    |list = [
        :
            一个块状文本字面量
        :
            另一个块状文本字面量
        "一个字符串", 1919
    ]
    list中有两个块状文本、一个字符串、一个数字。

与Python不同,一旦列表字面量/形参列表跨多行,里面的内容就必须缩进一层。不过,普通的和多行的列表字面量/形参列表可以相互包含:

|def main:
    |function_with_parameters(
        "这是第一个参数"
        [1, [
            "包含很长很长很长很长很长很长很长很长很长很长的字符串的列表字面量也应该使用多行写法"
            "水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水水"
        ], 2, 3]
    )

文本的属性

还可以给文本设置属性,方法是在它前面加~,后面跟需要的属性,语法类似于Python中的命名参数。在soullc环境下,可以添加colorbgcolor属性:

|def main:
    |print ~color="red", bgcolor="#114514":
        Hello, world!

这种方法也可以用于整个函数,只要写在:`前即可。

|def main ~color="green":
    整个程序都是绿的!

这里的"red""#114514"等都是字符串;实际上,也可以用变量来当属性的值。soullc中可用的属性:

属性 含义 可能的值 默认值
color 字体颜色 0~15的整数,或CSS颜色值字符串 空字符串
bgcolor 文字背景高亮颜色 0~15的整数,或CSS颜色值字符串 空字符串
pause (仅块状文本)换行前是否等待用户按任意键 布尔值 True
delay 每显示一个字符后延时的毫秒数 自然数 45

运算符

Richard Markup v3中的运算符有(运算顺序由先到后):

  1. 索引和函数调用――a[b]a( ),左结合
  2. 乘方――a**b,右结合
  3. 正负――+a-a,右结合
  4. 乘除――a * ba / ba // ba % b,左结合
  5. 加减――a + ba - b,左结合
  6. 比较――a == ba < ba <= ba > ba >= ba != b,无结合
  7. 逻辑非――not a,右结合
  8. 逻辑与――a and b,左结合
  9. 逻辑或――a or b,左结合

这些运算符的结合律都与Python相同。左结合a + b + c会按(a + b) + c计算;右结合a**b**c会按a**(b**c)计算;无结合a < b < c会按(a < b) and (b < c)计算。

赋值操作不是运算符,一个赋值操作就是一个语句。赋值操作有:

= += -= *= /= //= %= **=

没有++--,和Python一样,++a只是+(+a)

没有逗号运算符,所以不可以写:

|def main:
    |a, b = 1, 2 # 逗号无效

不过可以用分号来在一行写两个语句:

|def main:
    |a = 1; b = 2

函数参数 [WIP]

函数参数的写法与Python基本相同,只是没有参数的函数定义可以省略括号。

|def function_with_parameter(param):
    # ...

通过给参数指定默认值可以把它变成一个可选参数,可选参数必需排在最后:

|def function_with_parameters(param1, param2="默认值"):
    # ...

流程控制

在块状逻辑中,if――elif――else块这样表示:

|def main:
    |score = 2**25 # 假设得分是2的25次方(
    #
    |if score >= 60000000:
        您六千万分了
    |elif score >= 30000000:
        您三千万分了
    |else:
        您没到三千万分()

行内写法则需要把“冒号加缩进”改成两个`

|def main:
    |beers = 2
    {if beers == 0 `No` else `{print beers}`} bottle{if beers > 1 `s`} of beer on the wall.

也有for循环,但是没有range;要循环指定次数只能用while手动实现,for只能遍历列表。

|def main:
    |for i in [1, 2, 3]:
        |print i
    
    |i = 1
    |while i <= 3:
        |print i
        |i += 1
    
    |i = 1
    {while i <= 3 `{print i; i += 1}`}

以下是经典的“FizzBuzz”程序:

|def main:
    |a = 1
    |while a <= 100:
        |modThree = a % 3
        |modFive = a % 5
        |if modThree != 0 && modFive != 0:
            |print a
        |else:
            {if modThree == 0 `Fizz`; if modFive == 0 `Buzz`}
        |a += 1