介绍一个很干净的语言。
Hello World
先看它的 Hello World 。
没看错。这个 Whitespace 语言的原语只有空格,制表符,还有换行。
语法
参考 Whitespace 语言官方教程 整理的 BNF 如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| Program ::= <Statement>{Statement}
Statement ::= <IMP>
IMP :: = <StackManipulation><SMCommand> | <Arithmetic><AriCommand> | <HeapAccess><HACommand> | <FlowControl><FCCommand> | <I/O><IOCommand>
StackManipulation ::= <Space>
SMCommand ::= <Push><Number> | <Duplicate> | <Swap> | <Discard>
Push ::= <Space>
Number ::= <Sign><Digit><End>
Sign ::= <Space> | <Tab>
Digit ::= <Space>{Digit}|<Tab>{Digit}
End ::= <LF>
Duplicate ::= <LF><Space>
Swap ::= <LF><Tab>
Discard ::= <LF><LF>
Duplicate ::= <LF><Space>
Arithmetic ::= <Tab><Space>
AriCommand ::= <Addition> | <Subtraction> | <Multiplication> | <IntegerDivision> | <Modulo>
Addition ::= <Space><Space>
Subtraction ::= <Space><Tab>
Multiplication ::= <Space><LF>
IntegerDivision ::= <Tab><Space>
Modulo ::= <Tab><Tab>
HeapAccess ::= <Tab><Tab>
HACommand ::= <Store><Retrieve>
Store ::= <Space>
Retrieve ::= <Tab>
FlowControl ::= <LF>
FCCommand ::= <Mark><Label> | <Call><Label> | <Jmp><Label> | <Jz><Label> | <Js><Label> | <SubroutineEnd> | <ProgramEnd>
Mark ::= <Space><Space>
Label ::= <LabelName><End>
LabelName ::= <Space>{LabelName}|<Tab>{LabelName}
Call ::= <Space><Tab>
Jmp ::= <Space><LF>
Jz ::= <Tab><Space>
Js ::= <Tab><Tab>
SubroutineEnd ::= <Tab><LF>
ProgrameEnd ::= <LF><LF>
I/O ::= <Tab><LF>
IOCommand ::= <OutputChar> | <OutputNumber> | <ReadChar> | <ReadNumber>
OutputChar ::= <Space><Space>
OutputNumber ::= <Space><Tab>
ReadChar ::= <Tab><Space>
ReadNumber ::= <Tab><Tab>
Space ::= " "
Tab ::= "\t"
LF ::= "\n"
|
不熟悉 BNF 可以直接看下面的图表。
IMP |
Command |
Meaning |
IMP Meaning |
[Space] |
[Space][Number] |
Push the number onto the stack |
Stack Manipulation |
[Space] |
[LF][Space] |
Duplicate the top item on the stack |
Stack Manipulation |
[Space] |
[LF][Tab] |
Swap the top two items on the stack |
Stack Manipulation |
[Space] |
[LF][LF] |
Discard the top item on the stack |
Stack Manipulation |
[Tab][Space] |
[Space][Space] |
Addition |
Arithmetic |
[Tab][Space] |
[Space][Tab] |
Subtraction |
Arithmetic |
[Tab][Space] |
[Space][LF] |
Multiplication |
Arithmetic |
[Tab][Space] |
[Tab][Space] |
Integer Division |
Arithmetic |
[Tab][Space] |
[Tab][Tab] |
Modulo |
Arithmetic |
[Tab][Tab] |
[Space] |
Store |
Heap access |
[Tab][Tab] |
[Tab] |
Retrieve |
Heap access |
[LF] |
[Space][Space] |
Mark a location in the program |
Flow Control |
[LF] |
[Space][Tab] |
Call a subroutine |
Flow Control |
[LF] |
[Space][LF] |
Jump unconditionally to a label |
Flow Control |
[LF] |
[Tab][Space] |
Jump to a label if the top of the stack is zero |
Flow Control |
[LF] |
[Tab][Tab] |
Jump to a label if the top of the stack is negative |
Flow Control |
[LF] |
[Tab][LF] |
End a subroutineand transfer control back to the caller |
Flow Control |
[LF] |
[LF][LF] |
End the program |
Flow Control |
[Tab][LF] |
[Space][Space] |
Output the character at the top of the stack |
I/O |
[Tab][LF] |
[Space][Tab] |
Output the number at the top of the stack |
I/O |
[Tab][LF] |
[Tab][Space] |
Read a character and place it in the location given by the top of the stack |
I/O |
[Tab][LF] |
[Tab][Tab] |
Read a number and place it in the location given by the top of the stack |
I/O |
所以这是一个将特定序列的空白符转成指令的语言。
比如
表示将栈顶数字以 ASCII 的形式输出。
解析 Hello World
空白符看起来比较不方便,将 Hello World 代码中空格替换为 [Space] ,制表符替换为 [Tab] ,换行替换为 [LF] 。
整理后如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| [Space][Space][Space][Tab][Space][Space][Tab][Space][Space][Space][LF] 数字压栈 0100 1000 也就是数字 72 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 72 也就是 H
[Space][Space][Space][Tab][Tab][Space][Space][Tab][Space][Tab][LF] 数字压栈 00 0110 0101 也就是数字 101 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 101 也就是 e
[Space][Space][Space][Tab][Tab][Space][Tab][Tab][Space][Space][LF] 数字压栈 00 0110 1100 也就是数字 108 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 108 也就是 l
[Space][Space][Space][Tab][Tab][Space][Tab][Tab][Space][Space][LF] 数字压栈 00 0110 1100 也就是数字 108 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 108 也就是 l
[Space][Space][Space][Tab][Tab][Space][Tab][Tab][Tab][Tab][LF] 数字压栈 00 0110 1111 也就是数字 111 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 111 也就是 o
[Space][Space][Space][Tab][Space][Tab][Tab][Space][Space][LF] 数字压栈 0 0010 1100 也就是数字 44 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 44 也就是 ,
[Space][Space][Space][Tab][Space][Space][Space][Space][Space][LF] 数字压栈 0 0010 0000 也就是数字 32 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 32 也就是 空格
[Space][Space][Space][Tab][Tab][Tab][Space][Tab][Tab][Tab][LF] 数字压栈 00 0111 0111 也就是数字 119 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 119 也就是 w
[Space][Space][Space][Tab][Tab][Space][Tab][Tab][Tab][Tab][LF] 数字压栈 00 0110 1111 也就是数字 111 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 111 也就是 o
[Space][Space][Space][Tab][Tab][Tab][Space][Space][Tab][Space][LF] 数字压栈 00 0111 0010 也就是数字 114 输出字符 r [Tab][LF][Space][Space] 输出栈顶字符 ASCII 114 也就是 r
[Space][Space][Space][Tab][Tab][Space][Tab][Tab][Space][Space][LF] 数字压栈 00 0110 1100 也就是数字 108 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 108 也就是 l
[Space][Space][Space][Tab][Tab][Space][Space][Tab][Space][Space][LF] 数字压栈 00 0110 0100 也就是数字 100 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 100 也就是 d
[Space][Space][Space][Tab][Space][Space][Space][Space][Tab][LF] 数字压栈 0 0010 0001 也就是数字 33 压栈 [Tab][LF][Space][Space] 输出栈顶字符 ASCII 33 也就是 !
[LF][LF][LF] 程序结束符号
|
这个 Hello World 代码很简单,只是简单的入栈出栈,没有用到跳转等复杂的功能。
最后
这个语言最大的作用是……