文言文编程进阶

2017gdgzoi999

2020-01-13 18:51:19

Tech. & Eng.

序言

本文章主要是用以补充文言文浅谈的内容。

注:阅读前请先了解文言文浅谈的内容。

以最新版为准,不保证洛谷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结束)

如:

若三不大於五者。
    吾有一言。曰「「想当然」」。書之。
若非。
    吾有一言。曰「「电脑出锅」」。書之。
云云。

相当于

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])只用带入原函数的后三个参数就可以了。

附加:函数嵌套的一种简易方法

Part 7 结构体

声明:吾有一物。名之曰「结构体」。

带内容声明:

吾有一物。名之曰「结构体」。其物如是。
    物之「「数」」者。數曰一。
    物之「「文」」者。言曰「「字符串」」。
    ...(声明结构体各个内容)
是謂「结构体」之物也。

用法与数组类似。

Part 8 标准库

调用标准库前声明:吾嘗觀「「...(库名)」」之書。方悟「...(调用函数名)」之義。声明后可以像正常函数一样调用。

也可以一次声明多个:吾嘗觀「「算經」」之書。方悟「正弦」「餘弦」之義。

调用特定文件的语法举例:吾嘗觀「「codes」」中「「luogu」」中「「p1001」」之書。调用codes/luogu/p1001

标准库所有函数

官方说明·导入

算經

算经库提供了一些数学函数。

部分标准库函数:

函数 对应
取底除 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);

宏定义: 或云「「宏名称」」。 蓋謂「「替换内容」」。

官方说明

比如:或云「「書「甲」焉」」。 蓋謂「「吾有一言。曰「甲」。書之」」。

相当于#define output(str) cout<<str

异常处理(try-catch语句)

官方说明

示例

try语句:姑妄行此。表示需检测异常语句段开始。

throw语句:嗚呼。「「异常内容」」之禍。表示检测到异常,跳到catch段处理。相当于throw "error";

catch语句:如事不諧。表示检测到异常后执行的代码块开始。

catch语句内判断异常内容的特殊if语句:豈「「异常内容」」之禍歟。

上述特殊if语句对应的else不知何禍歟。

上述else获得具体异常信息:不知何禍歟。名之曰「异常信息」。

catch语句结束:乃作罷。

通俗点,就是先执行trycatch之间的代码,这一段代码中若满足一些条件使得其中的throw语句被执行了,那么忽略之后所有trycatch间的代码,执行catch段代码。如果没有,则catch段代码不被执行。

文言官方文件附带

官方IDE

Part 11 例子

A+B

施「require('fs').readFileSync」於「「/dev/stdin」」。名之曰「數據」。
施「(buf => buf.toString().trim())」於「數據」。昔之「數據」者。今其是矣。
施「(s => s.split(' '))」於「數據」。昔之「數據」者。今其是矣。

夫「數據」之一。取一以施「parseInt」。名之曰「甲」。
夫「數據」之二。取一以施「parseInt」。名之曰「乙」。

加「甲」以「乙」。書之。

输入模板

大常数线段树

函数、数组综合

P5834 MooBuzz

总结

文言是一种广受欢迎的新生编程语言,优缺点总结如下:

优点

缺点