llang
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,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;
];