文言文编程进阶

2017gdgzoi999

2020-01-13 18:51:19

Personal

## 序言 本文章主要是用以补充[文言文浅谈](https://www.luogu.com.cn/blog/fishstack/wen-yan-wen-ye-neng-bian-cheng-post)的内容。 注:阅读前请先了解文言文浅谈的内容。 以最新版为准,不保证洛谷IDE支持全部内容。 ## Part 1 输入输出进阶 输出和输入是一切语言的基本操作。文言的输出简洁,输入则稍微繁琐。 ### 输出 输出语句的标志:`書之。` `吾有一數。...書之。`:输出数字,阿拉伯形式。 数字的范围是 $[-2^{256},2^{256})$。 其中`...`中,表示常量使用中文表示,也可使用变量形式。 如:`吾有一數。曰三十七。書之。`输出 $37$。 `吾有一言。...書之。`:输出字符串。 字符串表示为`「「...」」`形式。(注意有二层括号) 如:`吾有一言。曰「「字符串」」。書之。`输出`字符串`。 以上每次“书之”语句的输出各占一行。为了在一行内输出多个数字,可以使用以下语句: `吾有三數。曰三千二百四十一。曰五百五十。曰一千零五。書之。` 输出`3241 550 1005`。 ### 输入 输入由于还未设专门函数,使用Javascript函数完成。 先看一下A+B Problem给的输入: ``` 施「require('fs').readFileSync」於「「/dev/stdin」」。名之曰「數據」。 施「(buf => buf.toString().trim())」於「數據」。昔之「數據」者。今其是矣。 施「(s => s.split(' '))」於「數據」。昔之「數據」者。今其是矣。 注曰。「「文言尚菜,無對象之操作,故需 JavaScript 之语法」」。 夫「數據」之一。取一以施「parseInt」。名之曰「甲」。 夫「數據」之二。取一以施「parseInt」。名之曰「乙」。 ``` 其中注曰之前的函数不用管(`split`除外)。 讲解:`「(s => s.split(' '))」`将数据拆分,以某个符号为界限(注意这个符号不在函数结果之内)。 `「parseInt」`将字符串转换为数字。 一些语法会在后提到。 先给一个得到一行数字的函数。 ``` 吾有一術。名之曰「输入」。是術曰。 施「require('fs').readFileSync」於「「/dev/stdin」」。名之曰「入」。 施「(buf => buf.toString().trim())」於「入」。昔之「入」者。今其是矣。 施「(s => s.split('\n'))」於「入」。昔之「入」者。今其是矣。 乃得「入」也。 是謂「输入」之術也。 吾有一數。曰零。名之曰「其行」。 施「输入」。名之曰「初始输入」。 吾有一術。名之曰「得数」。是術曰。 吾有一列。名之曰「其数」。 加「其行」以一。昔之「其行」者。今其是矣。 夫「初始输入」之「其行」。名之曰「此行」。 施「(s => s.split(' '))」於「此行」。昔之「此行」者。今其是矣。 夫「此行」之長。名之曰「长」。 吾有一數。曰零。名之曰「下标」。 為是「长」遍。 加「下标」以一。昔之「下标」者。今其是矣。 夫「此行」之「下标」。名之曰「此数」。 施「parseInt」於「此数」。昔之「此数」者。今其是矣。 銜「其数」以「此数」。昔之「其数」者。今其是矣。 云云。 乃得「其数」也。 是謂「得数」之術也。 ``` 如果看过浅谈,应该不难理解:将初始输入用换行符拆分为各行;使用一个变量表示目前所在的行;每行要用时用空格拆分成各个小字符串;将小字符串转为数字后装入列表返回。 ## Part 2 变量 ### 声明 `吾有一數。曰一。名之曰「数」。`声明数字。相当于`int a=...` `吾有一言。曰「「字符串」」。名之曰「文」。`声明字符串。 `吾有一爻。曰陽。名之曰「布尔型」。`声明布尔型变量。 (布尔值表示:`陽`为真,`陰`为假) `吾有一元。...名之曰「自动类型」。`声明的变量自动判断类型,相当于C++11的`auto`。 也可以用这个形式:`有數一。名之曰「数」。` 多个变量同时声明:`吾有三數。曰一。曰二。曰三。名之曰「数甲」曰「数乙」曰「数丙」。` ### 自动变量 `其`:最近的算出的答案。 ### 使用 用括号`「」`括变量名。如`「变量」`。 特别地,使用自动变量`其`时不带括号。 ### 赋值 `...昔之「变量」者。今其是矣。`赋前面最近所算出的答案。 `昔之「变量」者。今...是矣。`赋为此语句给出的值。相当于`var=...` ## Part 3 运算 ### 数字运算 `加...以...。`对应`+`运算。 `减...以...。`对应`-`运算。 `乘...以...。`对应`*`运算。 `除...以...。`对应`/`运算。注意此运算保留小数。 `除...以...。所餘幾何。`对应`%`(取模)运算。 ### 大小关系判断 `...大於...`对应`>`运算。 `...不大於...`对应`<=`运算。 `...小於...`对应`<`运算。 `...不小於...`对应`>=`运算。 `...等於...`对应`==`运算。 ### 布尔值运算 `夫...中有陽乎。`对应`||`(或)运算。 `夫...中無陰乎。`对应`&&`(与)运算。 如:`夫「布尔值甲」「布尔值乙」中有陽乎。` ## Part 4 分支与循环 ### 分支语句 ``` 若...(条件)者。 ...(真时代码块) 若非。(等同else,可选) ...(假时代码块,可选) 云云。(if结束) ``` 如: ``` 若三不大於五者。 吾有一言。曰「「想当然」」。書之。 若非。 吾有一言。曰「「电脑出锅」」。書之。 云云。 ``` 相当于 ```cpp if (3<=5) printf("of course"); else printf("bad computer"); ``` `或若...`:相当于`else if`语句。 `若其然者`/`若其不然者`:当自动变量`其`不为零/为零时执行语句。 ### 循环语句 `為是...(循环次数)遍。`声明一个执行特定次的循环开始。 相当于`for(i=0;i<n;++i)` `恆為是。`声明一个死循环的开始。可以用`乃止。`语句结束。 相当于`for(;;)` `云云。`声明循环部分结束。(和分支语句一样) `乃止。`跳出最内的一个循环,相当于`break`语句。 `乃止是遍。`返回到循环开始,相当于`continue`语句。 ## Part 5 数组 ### 声明 `吾有一列。名之曰「数组」。` 相当于`[类型未知] array={};` 声明带赋值:`吾有一列。名之曰「数组」。充「数组」以零。以一。` 相当于`[类型未知] array={0,1};` ### 调用 查询数组内容:`夫「数组」之...(下标)`返回容器特定下标的值。下标从一开始。如`夫「数组」之一`,``夫「容器」之「「字符串」」``。 数组内容更改:`昔之「数组」之...(下标)者。今...是矣。` 查询数组大小:`夫「数组」之長。` 相当于`list.size()` 连接不同数组或数组与元素连接:`銜「数组」以...(连接目标)。`此函数将结果数组返回,不改变原有数组。 声明遍历数组内容的循环开始:`凡「数组」中之「变量」。`(也是`云云。`结束) 将数加在数组后面:`充「数组」以一。` `充「数组」以一。以二。`。 相当于`array.push(1);` `array.push(1);array.push(2);` ## Part 6 函数 ### 声明 函数声明开始:`吾有一術。名之曰「函数」。是術曰。` 相当于`[返回值类型未知] function()` 带参数: `吾有一術。名之曰「函数」。欲行是術。必先得一數。曰「参数」。是術曰。` 相当于`[返回值类型未知] function(int var_a)` `吾有一術。名之曰「函数」。欲行是術。必先得...(参数个数)數。曰「参数一」。曰「参数二」。...(声明各种参数)是術曰。` 注:这里的参数类型也可以是字符串(`言`)、布尔值等。 函数结束声明:`是謂「函数」之術也。` 格式: ``` 吾有一術。名之曰「函数」。...(参数声明,可选)是術曰。 ...(函数内容) 是謂「函数」之術也。 ``` 比如这就是一个求线段树右儿子的函数(注意参数不是以指针形式传入的) ``` 吾有一術。名之曰「其右」。欲行是術。必先得一數。曰「节点」。是術曰。 乘「节点」以二。昔之「节点」者。今其是矣。 加「节点」以一。昔之「节点」者。今其是矣。 乃得「节点」也。 是謂「其右」之術也。 ``` 返回结果:`乃得...(函数返回值)也。`注意编译时它自带右括号,因此在分支或循环语句末尾时要处理(把`云云。`删去)。 当返回不带返回值时,使用`乃歸空無。`语句。 ### 调用 函数的调用非常简洁。`施「函数」。`(无参)`施「函数」於...。於...(代入各参数)`(有参) 尽管函数声明时规定了参数个数,但是调用时参数个数可以少于规定个数。这将返回一个函数,表现为原函数前面一些参数固定的版本。 举例: ``` 吾有一術。名之曰「修改」。欲行是術。必先得六數。曰「节点」。曰「左」。曰「右」。曰「改左」。曰「改右」。曰「增值」。是術曰。[1] ... 是謂「修改」之術也。 ... 施「修改」於一。於一。於「树长」。名之曰「简易修改」。[2] ... 施「简易修改」於「改左」。於「改右」。於「增值」。...[3] ``` 说明:上面代码中[1]处声明了线段树的修改函数,其中有六个参数。考虑到主函数中调用此函数前三个参数是固定的,于是在[2]处通过不完全参数定义了新函数`「简易修改」`,调用简易版函数时([3])只用带入原函数的后三个参数就可以了。 附加:[函数嵌套的一种简易方法](https://github.com/wenyan-lang/wenyan/blob/master/documentation/Nested-Function-Calls.md) ## Part 7 结构体 声明:`吾有一物。名之曰「结构体」。` 带内容声明: ``` 吾有一物。名之曰「结构体」。其物如是。 物之「「数」」者。數曰一。 物之「「文」」者。言曰「「字符串」」。 ...(声明结构体各个内容) 是謂「结构体」之物也。 ``` 用法与数组类似。 ## Part 8 标准库 调用标准库前声明:`吾嘗觀「「...(库名)」」之書。方悟「...(调用函数名)」之義。`声明后可以像正常函数一样调用。 也可以一次声明多个:`吾嘗觀「「算經」」之書。方悟「正弦」「餘弦」之義。` 调用特定文件的语法举例:`吾嘗觀「「codes」」中「「luogu」」中「「p1001」」之書。`调用`codes/luogu/p1001`。 [标准库所有函数](https://github.com/wenyan-lang/wenyan/blob/master/documentation/Standard-Lib.md) [官方说明·导入](https://github.com/wenyan-lang/wenyan/blob/master/documentation/Importing.md) ### `算經`库 算经库提供了一些数学函数。 部分标准库函数: | 函数 | 对应 | | :----------: | :----------: | | `取底除` | `floor(a/b)`,同时返回商和余数 | | `正負` | 符号(`1`(正)`0`(零)`-1`(负)) | | `取整除` | `round(a/b)`(四舍五入),同时返回商和余数 | | `取底` | `floor()` | | `取整` | `round()` | | `取頂` | `ceil()` | | `絕對` | `abs()`,`fabs()` | | `正弦` | `sin()` | | `餘弦` | `cos()` | | `反正弦` | `asin()` | | `反餘弦` | `acos()` | | `正切` | `tan()` | | `反正切` | `atan()` | | `勾股求角` | `atan2()` | | `勾股求弦` | `hypot()` | | `對數` | `log()` | | `指數` | `exp()` | | `冪` | `pow()` | | `平方根` | `sqrt()` | ### `易經`库 易经库提供了随机数。 | 函数 | 对应 | | :----------: | :----------: | | `運` | `srand()` | | `占` | `rand()` | ### `畫譜`库 书谱库提供了画图方法。画图在结构体上进行。 函数:`備紙` `擇筆` `蘸色` `落筆` `運筆` `提筆` `裱畫`。由于时间有限,故不再对这些函数深入研究。 最终图像输出:`施「裱畫」於「图像」於「「out」」。` ### `列經`库 提供了数组操作。这里只提供部分常用操作。 | 函数 | 对应 | | :----------: | :----------: | | `遍施` | 对数组内所有数`x`执行`x=function(x)`后返回 | | `排序` | `sort()` | | `倒序` | `reverse()` | ### `曆法`库 历法库提供时间操作。 `今何紀元時` `言今之日時` `今年何年` `今年何年號` `今年何干支` `今時何時` `今時何小時` `今刻何刻` `今分何分` `今秒何秒` 等函数。很大一部分都是古人算法,现在不常用 调用`言今之日時`函数可以直接输出现在的时间。 ## Part 9 注释 `注曰。「「注释内容」」。` `批曰。「「注释内容」」。` `疏曰。「「注释内容」」。` 它们相当于其他语言中被`/*`,`*/`括起的注释。 ## Part 10 杂项 连接两个字符串:`加「字符串甲」以「字符串乙」。`相当于`strcat(str_a,str_b);` 宏定义: `或云「「宏名称」」。 蓋謂「「替换内容」」。` [官方说明](https://github.com/wenyan-lang/wenyan/blob/master/documentation/Macros.md) 比如:`或云「「書「甲」焉」」。 蓋謂「「吾有一言。曰「甲」。書之」」。` 相当于`#define output(str) cout<<str` ### 异常处理(`try-catch`语句) [官方说明](https://github.com/wenyan-lang/wenyan/blob/master/documentation/Try-Catch.md) [示例](https://wy-lang.org/ide?example=try) `try`语句:`姑妄行此。`表示需检测异常语句段开始。 `throw`语句:`嗚呼。「「异常内容」」之禍。`表示检测到异常,跳到`catch`段处理。相当于`throw "error";` `catch`语句:`如事不諧。`表示检测到异常后执行的代码块开始。 在`catch`语句内判断异常内容的特殊`if`语句:`豈「「异常内容」」之禍歟。` 上述特殊`if`语句对应的`else`:`不知何禍歟。` 上述`else`获得具体异常信息:`不知何禍歟。名之曰「异常信息」。` `catch`语句结束:`乃作罷。` 通俗点,就是先执行`try`到`catch`之间的代码,这一段代码中若满足一些条件使得其中的`throw`语句被执行了,那么忽略之后所有`try`到`catch`间的代码,执行`catch`段代码。如果没有,则`catch`段代码不被执行。 ### 文言官方文件附带 [官方IDE](http://wenyan-lang.lingdong.works/ide.html) - 把代码渲染成古文样式(浅谈已说) - 将输出的数转为汉字的功能 - 一些样例文件(官方IDE中可以找到) ## Part 11 例子 A+B ``` 施「require('fs').readFileSync」於「「/dev/stdin」」。名之曰「數據」。 施「(buf => buf.toString().trim())」於「數據」。昔之「數據」者。今其是矣。 施「(s => s.split(' '))」於「數據」。昔之「數據」者。今其是矣。 夫「數據」之一。取一以施「parseInt」。名之曰「甲」。 夫「數據」之二。取一以施「parseInt」。名之曰「乙」。 加「甲」以「乙」。書之。 ``` [输入模板](https://www.luogu.com.cn/paste/mp6yzbxk) [大常数线段树](https://www.luogu.com.cn/paste/okh7z6ru) [函数、数组综合](https://www.luogu.com.cn/paste/mp6yzbxk) [P5834 MooBuzz](https://www.luogu.com.cn/blog/2017gdgzoi999/solution-p5834) ## 总结 文言是一种广受欢迎的新生编程语言,优缺点总结如下: ### 优点 - 对于中国人来说,代码可以作为注释,容易理解程序作用 - 弘扬中华传统文化 ### 缺点 - 不方便输入,如一些繁体字、特殊括号等 - 一些函数如输入还未完善