llang

XiLaiTL大约 8 分钟

llang

author: xiaodou8593

coder: XiLaiTL

llang世界只有列表

但是有两种列表

一种称为普通列表,它本身住在llang世界里,掌握呼唤它的魔法就可以将它召唤出来。

另一种成为语句常量列表,它一般肩负使命,执行完使命之后就默默消失,它一般以";"结尾。

列表由列表名和列表内容组成

列表的定义语句list_name:[list_content1,list_content2];

a:[];
b:[a];
c:[a,b];
d'e:[a,b,c];

冒号前面定义了列表名,冒号后面定义了列表的内容。

列表的内容可以由上述两种列表组成

列表可以进行执行

列表的执行语句list_name;

a'b'c'd:[];
e:[a,b,c,d];
e;

列表将依次执行列表的所有内容。

例如第三句e;将依次执行a;b;c;d;因为a,b,c,d都是空列表,因此执行结束。

列表可以递归执行

llang不会检查列表的内容是否先于列表定义存在,只有在列表执行阶段才会判断列表内容是否是未定义的

a:[b];
b:[a];
a;

按照预期结果,应该会不断递归执行a。

同理,列表的内容可以包含列表本身。

a'b'c:[];
d:[a,b,c,d];
d;

按照预期结果,应该会不断递归执行a,b,c。

列表的第一个内容称为列表的值

这里介绍第三个语法,列表取内容。像C语言一样,列表可以通过下标取内容list_name[0]这样就取到了列表的第一个内容。

a'b:[];
d:[a,b];
d[0];

按预期结果,应该会a。

推理可得,可以通过list_name[-1]取到列表最后一项内容,以此类推。

当列表的值是列表本身时,称为常量列表

a:[a,b,c,d];
a;

由于a的值是a本身,所以a是常量列表,执行a不再附带其他操作。

基本常量列表

基于常量列表的特性,我们为某些特定的常量设计了响应的操作。详见附录。

(由于这些常量定义比较复杂,llang设计了语句常量的语法糖,所以这部分先跳过啦!)

语句常量列表

我们第一次学习的定义语句本身也是一个列表!

也就是list_name:[list_content];这个语句本身,也是一个列表!

不仅如此,列表的执行操作如list_name;这个语句本身,也是一个列表!

同时,为了方便实现上述基本语句常量的操作,我们引入了新的语法以及语句常量列表。

定义语句常量列表

list_name:[list_content];

列表内容为普通列表和语句常量列表

执行语句常量列表

list_name;

移除语句常量列表

list_name>;

将移除列表的最后一项内容

追加语句常量列表

list_a<list_b;

将list_b作为列表list_a的最后一项列表内容

作用语句常量列表

list_a->list_b;

读作“list_a作用于list_b”

这里引入已经定义好的全局列表@。根据上面的基本常量的作用,这个语句常量列表的作用将被翻译为:

@<list_b;
list_a;
@>;

首先将list_b添加到全局列表@中,接着执行list_a,然后将list_b从@中移除。

可以看见,如果想要让list_a作用于list_b,list_a必然和@的最后一项内容有关系。因此我们可以这样定义列表list_a

list_a:[@[-1]];

只要list_a的列表内容引用到@[-1],我们就可以利用作用于的语法代替上述3个句子。

删除语句常量列表

del list_name;或者~list_name;

将列表从全局中删除

赋值语句常量列表

list_a=list_b;

自增语句常量列表

list_name++;

将list_name列表向右转动一次,例如:

a:[2,3,4,5,1];
a++;
a;

将会依次执行2,3,4,5,1

特殊的基本常量

print

没有特殊的语法。

用于输出列表名的连接。如

print:[print,a,b,c];
print;

将输出abc

out

out->list_name;

用于输出列表内容。具体的语法解释见第二节。

a:[1,2,3,4];
out->a;

将输出a:[1,2,3,4];

0,1,2,3,4,5,6,7,8,9,10,11

1->list_name;

将列表向左转动n次

a:[1,2,3,4];
2->a;
out->a;

将输出a:[3,4,1,2]

普通列表

终于回到介绍我们的普通列表了。

列表名指代普通列表

list_name

列表取内容指代普通列表

list_name[1]

例如,a:[b,c,d,e];使用a[0]将会指代b列表,而不是a[0]本身作为列表!

匿名列表作为普通列表

[a,b,c,d]

连接列表内容指代普通列表

&list_name

这里添加了新的语法,例如a:[t,e,s,t];使用&a将会连接列表内容的子列表名,指代列表test

test:[];
a:[t,e,s,t];
&a;

应该会执行列表test。

两种列表的联系和区别

既然两种类型的语法都称为列表,那两种列表应该有共同的特性——那就可以作为列表的内容。

a:[out->a;];
a;

将会首先执行a,因此执行out->a;,因此结果是a:[out->a;];

两种列表的区别

我们先来对比一下两个列表

b:[out->b;];
a:[b];
c:[b;];
a;
c;

在这里,a和c的执行结果相同,但是执行却是由不同的逻辑主导的。

对于a来说,b的执行是因为执行a,所以执行a的列表内容b。

对于c来说,b的执行是因为执行c,所以执行c的列表内容b;,因为执行b;,所以执行b。

在第二中情况下,b不作为c的子内容执行,这是最浅显的区别。

实现HelloWorld

现在,我们掌握了llang最基本的语法,可以实现HelloWorld了。

helloworld:[];
print:[print,helloworld];
print;

多文件操作以及引入标准库

没错,每一个文件也被llang视为一个列表!

文件名就是表名。

当你要使用其他文件内的内容时,只需要#file_name;

相当于调用列表的语句,就可以引入其他文件的内容了!

#std;
help->help;

像这样,引入标准库的内容,标准库内容详见std.llg

comment常量

comment:[comment,play with me];
comment;

像注释一样!会输出play with me

llang的函数实现

不难发现,我们的函数可以由3种方式实现

利用选定者,(全局列表@)实现函数

可以利用到作用于的语法糖

定义: print_test:[@[-1]];
调用: print_test->helloworld;


定义: print_:[print:[print,@[-1]];,print;];
调用: print_->list;

利用列表,实现函数

利用llang本质的实现方式。缺点是需要使用到两个列表

例如实现库函数for:

定义:
for_condition:[];
for_program:[];
for:[for_condition,for_program];
for_run:[for[1],if[for[0][0],for[0][1],0,for_run];];

调用: 一直执行a,直到b[0]是d
for:[[b[0],d],a]; 
for_run;

利用递归和出入列表,实现函数

列表引用参数的位置在于列表本身的末尾,这样就可以通过list_name[-1]等等索引到

helloworld:[];
badday:[b,a,d,d,a,y];
a:[print:[print,badday];print;];
b:[out->helloworld;];

TRUE:[TRUE[-2],TRUE>>;];
FALSE:[FALSE[-1],FALSE>>;];
IF:[(IF[-3]<IF[-2]'IF[-1];),IF[-3],IF>>>;];

IF<TRUE'a'b;
IF;

IF<FALSE'a'b;
IF;

附录:基本常量表

1.rotate_const
	序号		0~11
	定义		0:[0,1,2,3,4,5,6,7,8,9,10,11]
			1:[1,2,3,4,5,6,7,8,9,10,11,0]
			...
			11:[11,0,1,2,3,4,5,6,7,8,9,10]
	作用		将选定者列表转动指定次数。
			例如:
				a:[b,c,d];
				4->a;
				out->a;
			输出为"c,d,b"
 
			再例如:
				a:[b,c,d];
				@:[@,a];
				2;
				out->a;
			输出为"d,b,c"
 
2.select_const
	序号		12
	定义		@:[@,...,last]
	意义		标记last为选定者
	作用		被运行时,把全部列表拉入
			例如:
				@;
				out->@;
			输出为全部列表
 
3.char_const
	序号		13~40
	定义		a:[a];
			b:[b];
			c:[c];
			...
			z:[z];
			_:[_];
			 :[ ];
	意义		对应字符
	作用		被运行时,将对应字符输出
			例如:
				print:[h,e,l,l,o,_,w,o,r,l,d];
				print;
			输出为"hello_world"
 
4.define_const
	序号		41
	定义		::[:,...,value]
	作用		生成一个新列表,名为...,赋值为value列表。
			若该名字的列表已被定义,对其重新定义,赋值为value列表。
			例如:
				::[:,a,b,c];
				:;
				out->ab;
				out->c;
			输出为两行,且一致
 
			再例如:
				new test;
				print:[print,test,b,c];
				print;
				print:[b,c,d];
				print;
			输出为	"testbc"
				"bcd"
 
5.assign_const
	序号		42
	定义		=:[=,a,b]
	作用		将列表b赋值给列表a
			例如:
				=:[=,b,c];
				=;
				out->b;
				out->c;
			输出均为"c"
 
6.delete_const
	序号		43
	定义		del:[del,list]
	作用		若list列表不是初始自带常量,删除a列表
			例如:
				new test;
				list:[test,a];
				del:[del,test];
				del;
 
7.append_const
	序号		44
	定义		<:[<,a,b]
	作用		将b列表追加到a列表后
			例如:
				new test;
				<:[<,test,a];
				<;
				<:[<,test,b];
				<;
				out->test;
			输出为"a,b"
 
8.remove_const
	序号		45
	定义		>:[>,a]
	作用		移走a列表最后一项
			例如:
				new test;
				<:[<,test,a];
				<;
				<;
				>:[>,test];
				>;
				out->test;
			输出为"a"
 
9.impose_const
	序号		46
	定义		->:[->,a,b]
	作用		将b拉入@,使其成为选定者,运行a,将b拉出@
 
10.if_const
	序号		47
	定义		if:[if,i,v,a,b]
	作用		若i为v,运行a,否则运行b
 
11.out_const
	序号		48
	定义		out:[out]
	作用		输出选定者列表中的全部列表名字
 
12.print_const
	序号		49
	定义		print:[print,...]
	作用		输出print后全部列表名字的拼接

标准库

std.llg

comment:[comment,standard llang lib has been loaded];
comment;

help:[
    _usage:[];
    help_name:[@[-1],_usage];
    out->&help_name;
];
help_usage:[help->help;];

run:[
    _run:[];
    run_name:[@[-1],_run];
    &run_name;
];
run_run:[out->run_usage;];
run_usage:[run->run;];

choice:[];
true:[choice[-2]];
false:[choice[-1]];

logic:[];
same:[list_first,list_second];
same_run:[same_run,same[0],same[1]];
same_usage:[comment:[comment,same_run will push true or false to logic];comment;];

equal:[list_first,list_second];
equal_run:[same:[equal[0][0],equal[1][0]];same_run;];

and:[];
and_remind:[
    @[-1];
    and<logic[-1];
];
and_run:[
    choice:[];
    choice<and[-1]'and[-2];
    logic<and[-2][0];
];
and_usage:[
    a:[];
    b'd:[a];
    c:[b];
    equal:[b,c];
    and_remind->equal_run;
    equal:[b,d];
    and_remind->equal_run;
    out->and;
    and_run;
    out->logic;
];

or:[];
or_remind:[
    @[-1];
    or<logic[-1];
];
or_run:[
    choice:[];
    choice<or[-2]'or[-1];
    logic<or[-2][0];
];
or_usage:[out->and_usage;];

not:[];
not_remind:[
    @[-1];
    not<logic[-1];
];
not_run:[
    choice:[];
    choice<false'true;
    logic<not[-1][0];
];
not_usage:[out->and_usage;];

if:[if_condition,true_action,false_action];
if_run:[
    choice'logic:[];
    if[0];
    choice<if[1]'if[2];
    logic[0];
];
if_usage:[
    out->if'if_run;
    a:[a,b];
    b:[a[0]];
    same:[a,b[0]];
    true_action:[out->a;];
    false_action:[out->b;];
    if:[same_run,true_action,false_action];
    if_run;
    out->if_usage;
];

until:[until_condition,until_action];
until_run:[
    until_program:[];
    if:[until[0],0,until[1]'until_run;];
    if_run;
];
until_usage:[
    out->until'until_run;
    a:[1,2,3,4,5];
    b:[5,1,2,3,4];
    out->a'b;
    equal:[a,b];
    until_action:[1->a;out->a;];
    until:[equal_run,until_action];
    until_run;
    out->until_usage;
];


foreach:[foreach_list,foreach_action];
foreach_run:[
    foreach_end:[];
    foreach[0]<foreach_end;
    same:[foreach[0][0],foreach_end];
    until_action:[foreach[1],foreach[0]++;];
    until:[same_run,until_action];
    until_run;
];
foreach_usage:[
    out->foreach'foreach_run;
    a:[1,2,3,4,5];
    foreach:[a,out->a[0];];
    foreach_run;
    out->foreach_usage;
];


connect:[list_first,list_second];
connect_ans:[];
connect_run:[
    foreach:[connect[0],connect_ans<connect[0][0];];
    foreach_run;
    foreach:[connect[1],connect_ans<connect[1][0];];
    foreach_run;
];
connect_usage:[
    out->connect'connect_ans'connect_run;
    a:[1,2,3,4,5];
    b:[6,7,8,9,10];
    out->a'b;
    connect:[a,b];
    connect_run;
    out->connect_ans;
];
上次编辑于:
贡献者: XiLaiTL