简介
突发奇想地想设计一门编程语言,但又没学过编译原理只能整个解释型语言了,又一想符号计算也很麻烦,干脆整个汇编一样的语言算了,当然还得是有与众不同特点的语言,那就是代码运行的时候可以修改自身代码的语言。最后,名字就叫Y语言吧(Yelang)。由于Y语言设计的核心思想是能简单地实现解释器(确实简单,用Python半个小时就写了个简易解释器出来),所以实用性就别指望了,娱乐向娱乐向~
Y语言2.0版本来了
Y语言代码示例(输入一个数字,输出其阶乘)
//定义阶乘函数
def fac
add fac_ret 1
cpy fac_ans 1
cpy fac_i 0
at fac_loop
add fac_i 1
mul fac_ans fac_i
grt fac_gt fac_n fac_i
if fac_gt
go fac_loop
eif
go fac_ret
edf fac
//输入一个数字并调用函数
out #input\_a\_number:
in fac_n
num fac_n
at fac_ret
go fac
out #factorial\_of\_ fac_n #\_is:\_ fac_ans
基础
1.空格、换行、注释以及缩进
空格是Y语言语句中唯一的分隔符,指令与变量与常量之间均以空格分隔。
语句与语句之间用换行分隔,一行只能有一条语句。
注释以//打头,运行时跳过,空行同理。
缩进对代码运行无影响。
2.变量
所有变量都是无类型全局变量!!!
变量名可以由任何除空格以外的可打印ASCII字符组成,但有两个限制:不能以#打头、不能是纯数字或科学计数法数字。
例.
合法变量名:5a、¥f、y0、nino、@@@、-abc+1_=、QAQ、=w=
不合法变量名:#a、123、0.2、2e-5、.5、+9、.314e1
数据类型支持数字、字符串、列表三种
其中字符串均以#打头空格结尾,因此字符串中不能直接含有空格字符,可以用\_ 转义表示空格,此外\\ 表示 \、\n 表示换行、\t 表示制表符也按照惯例。
变量定义方法见下文。
3.行号和指令
Y语言的代码从头开始逐行运行,每行代码都对应一个行号,行号从0开始。每行语句的第一个单词即指令,其后都为指令需要的参数,指令指示解释器的行为,具体见下文。
指令和语法
指令可以分为基础指令、算数指令、逻辑指令和串指令四类共30条,所有指令运行时均不分大小写。
1.基础指令
- at:定位指令,接受一个变量名,将当前行号存入该变量。如 at var。
- go:跳转指令,接受一个参数,可以是数字常量或变量,将当前运行行跳转到数字对应行的下一行。如 go loop。
- def:定义指令,接受一个变量名,将当前行号存入该变量,同时忽略接下来的所有语句直到遇到对应edf语句,主要用于定义函数。如 def fun。
- edf:结束定义指令,接受一个变量名,与def配对使用,用于结束def的忽略语句状态。如 edf fun。
- if:条件指令,接受一个参数,若该参数为0则忽略接下来的所有语句直到遇到匹配的eif。如 if flag。
- eif:结束条件指令,不接受参数,与if配对使用,用于结束if的忽略语句状态,eif会匹配之前最近一个未被匹配的if。如 eif。
- cpy:赋值指令,接受一个变量名和一个参数,将第二个常量或变量的值存入第一个变量。如 cpy var #yelang或 cpy var1 var2。
- in:输入指令,接受若干个变量名,从键盘输入若干个字符串分别存入这些变量。如 in var1 var2 var3。
- out:输出指令,接受若干个参数,将这些常量或变量的值依次输出到屏幕。如 out var1 #abc_def var2。
- yec:译改指令,接受一个数字量和一个字符串量,将字符串量写入到数字量对应行的下一行代码,这条指令是文章开头提到的代码运行的时候可以修改自身代码的具体实现,也是Y语言最灵活的指令。如 yec var #out\_#var或 yec 10 codestr。
2.算数指令
- num:转数指令,接受若干个变量,将这些变量的值转换为数字,仅对字符串量有效。如 num str1 str2。
- add:加指令,接受一个变量和若干个数字量,将所有接受的数字量加到变量中。如 add var a b 3,相当于var += a + b + 3。
- sub:减指令,接受一个变量和若干个数字量,将所有接受的数字量从变量中减去。如 sub var a b 3,相当于var -= a + b + 3。
- mul:乘指令,接受一个变量和若干个数字量,将所有接受的数字量依次乘到变量中。如 mul var a b 3,相当于var *= a * b * 3。
- div:除指令,接受一个变量和若干个数字量,将变量依次除以所有接受的数字量。如 div var a b 3,相当于var /= a * b * 3。
- mod:模指令,接受一个变量和一个数字量,将变量模数字量的结果存到变量中。如 mod var 10,相当于var %= 10。
- pow:幂指令,接受一个变量和一个数字量,将变量的数字量幂结果存到变量中。如 pow var 10,相当于var = var ^ 10。
- int:取整指令,接受若干个变量,将这些变量的值取整,仅对数字量有效。如 int num1 num2。
3.逻辑指令
- and:与指令,接受一个变量名和若干个参数,将所有参数与运算的结果存入变量。如 and f a1 a2 a3,相当于 f = a1 and a2 and a3
- or:或指令,接受一个变量名和若干个参数,将所有参数或运算的结果存入变量。如 or f a1 a2 a3,相当于 f = a1 or a2 or a3
- not:非指令,接受若干个变量,对所有变量进行非运算。如 not a1 a2,相当于 a1 = !a1;a2 = !a2。
- grt:大于指令,接受一个变量名和两个同类量,若第一个量大于第二个则将1存入变量,否则存入0。如 grt f n 10,相当于 f = n > 10 ? 1 : 0。
- equ:等于指令,接受一个变量名和两个同类量,若第一个量等于第二个则将1存入变量,否则存入0。如 equ f n 10,相当于 f = n == 10 ? 1 : 0。
FAQ:为啥没有小于、小于等于、大于等于、不等于、异或同或指令?可以由,但没必要,都能用已有的指令组合出来,a < b ⇔ b > a,a >= b ⇔ a > b or a == b,a != b ⇔ not a == b,a xor b ⇔ (a and not b) or (not a and b)。这么说起来 and 和 or 都可以只留一个了,反正 a and b ⇔ not a or not b。
4.串指令
- str:字串指令,接受若干个变量,将这些变量的值转换为字符串。如 str var1 var2。
- lst:列表指令,接受一个变量名和一个数字量,创建长度为数字量的全0列表存入变量。如 lst list lengh。
- len:长度指令,接受一个变量名和一个字符串或列表量,将参数的长度存入变量中。如 len var #abc\_def,这里 var = 7。
- idx:索引指令,接受一个变量名、一个字符串或列表量和一个数字量,将字符串或列表量中索引为数字量的值存入变量中。如 idx var #abc\_def 3,这里 var 为一个空格的字符串。
- set:设值指令,一个字符串或列表变量、一个数字量和一个参数,将参数写入字符串或列表变量中索引为数字量的位置。如 set list 4 var。
PS:这个指令可能改变字符串长度,如 cpy s #abc;set s 1 #000;out s;将输出 a000b。 - cut:切片指令,接受一个变量名、一个字符串或列表变量和两个数字量,将字符串或列表变量从第一个数字量到第二个数字量之间(留头去尾)的值切片成新的字符串或列表存入变量。如 cut s #abcdef 1 4,这里 s = ’bcd‘。
- lnk:链接指令,接受一个字符串或列表变量和若干个同类量,将这些量依次追加到变量的结尾。如 lnk ss #\_22 #\_nino str,若 ss = ’ye‘、str = ’!‘ 则运行后 ss = ’ye 22 nino!‘。
Python实现的解释器
随便写了个解释器,可能有没处理到的异常和BUG。
class Var(str):
def __init__(self, s):
str.__init__(self)
self.s = s
def __str__(self):
return self.s
class YeInterpreter:
def __init__(self, source):
self.__code = open(source, 'r').readlines()
self.__vars = {}
self.__p = 0
self.__defname = None
self.__ifnum = 0
self.__actions = {'at': self.__at, 'go': self.__go, 'def': self.__def, 'edf': self.__edf,
'if': self.__if, 'eif': self.__eif, 'cpy': self.__cpy, 'in': self.__in,
'out': self.__out, 'add': self.__add, 'sub': self.__sub, 'mul': self.__mul,
'div': self.__div, 'mod': self.__mod, 'pow': self.__pow, 'int': self.__int,
'and': self.__and, 'or': self.__or, 'not': self.__not, 'grt': self.__grt,
'equ': self.__equ, 'num': self.__num, 'str': self.__str, 'lst': self.__lst,
'idx': self.__idx, 'set': self.__set, 'cut': self.__cut, 'lnk': self.__lnk,
'len': self.__len, 'yec': self.__yec}
self.__run()
def __run(self):
while self.__p < len(self.__code):
self.__execute(self.__p)
self.__p += 1
def __execute(self, ordernum):
action, *par = self.__code[ordernum].strip().split(' ')
action = action.lower()
par = self.__correct(par)
if not action or action.startswith('//'):
return
if self.__defname:
if action == 'edf':
if not par:
raise SyntaxError('Missing parameters at line {0}'.format(self.__p))
if par[0] == self.__defname:
self.__defname = None
return
if self.__ifnum > 0:
if action == 'if':
self.__ifnum += 1
elif action == 'eif':
self.__ifnum -= 1
if self.__ifnum < 0:
raise SyntaxError('Unmatched eif at line {0}'.format(self.__p))
return
if action in self.__actions:
try:
self.__actions[action](par)
except IndexError:
raise SyntaxError('Missing parameters at line {0}'.format(self.__p))
except KeyError as key:
raise NameError('Cannot find var: {0} at line {1}'.format(key, self.__p))
except TypeError as key:
raise TypeError('{0} at line {1}'.format(key, self.__p))
except ValueError as key:
raise TypeError('{0} at line {1}'.format(key, self.__p))
else:
raise NameError('Unknow action: {0} at line {1}'.format(action, self.__p))
def __correct(self, par):
for i in range(len(par)):
if par[i].startswith('#'):
par[i] = self.__tostr(par[i])
else:
try:
par[i] = int(par[i])
except ValueError:
try:
par[i] = float(par[i])
except ValueError:
par[i] = Var(par[i])
return par
@staticmethod
def __tostr(s):
res = ''
i = 1
while i < len(s):
if s[i] == '\\' and i + 1 < len(s):
if s[i + 1] == '\\':
res += '\\'
elif s[i + 1] == 'n':
res += '\n'
elif s[i + 1] == 't':
res += '\t'
elif s[i + 1] == '_':
res += ' '
else:
res += '\\' + s[i + 1]
i += 1
else:
res += s[i]
i += 1
return res
def __checkvar(self, p):
if not isinstance(p, Var):
raise NameError('{0} cannot be varname at line {1}'.format(p, self.__p))
def __value(self, par):
return self.__vars[par] if isinstance(par, Var) else par
def __at(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = self.__p
def __go(self, par):
if not isinstance(self.__value(par[0]), int) or self.__value(par[0]) < 0:
raise TypeError('{0} is not a index'.format(par[0]))
self.__p = self.__value(par[0])
def __cpy(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = self.__value(par[1])
def __def(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = self.__p
self.__defname = par[0]
def __edf(self, par):
raise SyntaxError('Unmatched edf at line {0}'.format(self.__p))
def __if(self, par):
if self.__value(par[0]) == 0:
self.__ifnum += 1
def __eif(self, par):
pass
def __in(self, par):
for p in par:
self.__checkvar(p)
self.__vars[p] = input()
def __out(self, par):
for p in par:
print(self.__value(p), end='')
def __add(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = sum(self.__value(p) for p in par)
def __sub(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] -= sum(self.__value(par[i]) for i in range(1, len(par)))
def __mul(self, par):
self.__checkvar(par[0])
tmp = 1
for i in range(1, len(par)):
tmp *= self.__value(par[i])
self.__vars[par[0]] *= tmp
def __div(self, par):
self.__checkvar(par[0])
tmp = 1
for i in range(1, len(par)):
tmp *= self.__value(par[i])
self.__vars[par[0]] /= tmp
def __mod(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] %= self.__value(par[1])
def __pow(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] **= self.__value(par[1])
def __int(self, par):
for p in par:
self.__checkvar(p)
if isinstance(self.__vars[p], (int, float)):
self.__vars[p] = int(self.__vars[p])
else:
raise TypeError('{0} isnot a num'.format(self.__vars[p]))
def __and(self, par):
self.__checkvar(par[0])
for i in range(1, len(par)):
if self.__value(par[i]) == 0:
self.__vars[par[0]] = 0
return
self.__vars[par[0]] = 1
def __or(self, par):
self.__checkvar(par[0])
for i in range(1, len(par)):
if self.__value(par[i]) != 0:
self.__vars[par[0]] = 1
return
self.__vars[par[0]] = 0
def __not(self, par):
for p in par:
self.__checkvar(p)
self.__vars[p] = 1 if self.__vars[p] == 0 else 0
def __grt(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = 1 if self.__value(par[1]) > self.__value(par[2]) else 0
def __equ(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = 1 if self.__value(par[1]) == self.__value(par[2]) else 0
def __num(self, par):
for p in par:
self.__checkvar(p)
if isinstance(self.__vars[p], (int, float)):
continue
try:
self.__vars[p] = int(self.__vars[p])
except ValueError:
try:
self.__vars[p] = float(self.__vars[p])
except ValueError:
raise ValueError('{0} cannot convert to num'.format(self.__vars[p]))
def __str(self, par):
for p in par:
self.__checkvar(p)
try:
self.__vars[p] = str(self.__vars[p])
except ValueError:
raise ValueError('{0} cannot convert to str'.format(self.__vars[p]))
def __lst(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = [0] * self.__value(par[1])
def __idx(self, par):
self.__checkvar(par[0])
self.__checkvar(par[1])
try:
self.__vars[par[0]] = self.__value(par[1])[self.__value(par[2])]
except IndexError:
raise ValueError('{0} out of range'.format(self.__value(par[2])))
except TypeError:
raise TypeError('{0} is not a index'.format(par[0]))
def __set(self, par):
self.__checkvar(par[0])
try:
if isinstance(self.__value(par[0]), list):
self.__value(par[0])[self.__value(par[1])] = self.__value(par[2])
elif isinstance(self.__value(par[0]), str):
self.__vars[par[0]] = self.__value(par[0])[:self.__value(par[1])] + str(
self.__value(par[2])) + self.__value(par[0])[self.__value(par[1]) + 1:]
except IndexError:
raise IndexError('{0} out of range'.format(self.__value(par[2])))
except TypeError:
raise TypeError('{0} is not a list or str'.format(par[0]))
def __cut(self, par):
self.__checkvar(par[0])
self.__checkvar(par[1])
try:
self.__vars[par[0]] = self.__value(par[1])[self.__value(par[2]): self.__value(par[3])]
except TypeError:
raise TypeError('{0} or {1} is not a index'.format(par[2], par[3]))
def __lnk(self, par):
self.__checkvar(par[0])
if isinstance(self.__vars[par[0]], list):
tmp = []
else:
tmp = ''
for i in range(1, len(par)):
try:
tmp += self.__value(par[i])
except TypeError:
raise TypeError('{0} connot link {1}'.format(par[0], par[i]))
self.__vars[par[0]] += tmp
def __len(self, par):
self.__checkvar(par[0])
self.__vars[par[0]] = len(self.__value(par[1]))
def __yec(self, par):
if not isinstance(self.__value(par[1]), str):
raise TypeError('can yec {}'.format(self.__value(par[1])))
try:
self.__code[self.__value(par[0]) + 1] = self.__value(par[1])
except IndexError:
raise ValueError('{0} out of range'.format(self.__value(par[0]) + 1))
except TypeError:
raise TypeError('{0} is not a index'.format(par[0]))
if __name__ == '__main__':
try:
YeInterpreter(input())
except Exception as e:
print('\n', e)
案例代码和运行效果
1、质数输出
输入一个数n,按每行20个输出小于n的所有质数。
def prime
//嵌套定义函数 isp 用于判断是否是质数
def isp
add isp_ret 1
cpy isp_t isp_n
pow isp_t 0.5
cpy isp_i 1
at isp_loop
add isp_i 1
grt isp_f isp_i isp_t
if isp_f
cpy isp_ans 1
go isp_ret
eif
cpy isp_f isp_n
mod isp_f isp_i
not isp_f
if isp_f
cpy isp_ans 0
go isp_ret
eif
go isp_loop
edf isp
add prime_ret 1
cpy prime_i 2
cpy prime_nop 0
at prime_loop
grt prime_f prime_i prime_n
if prime_f
go prime_ret
eif
//这里调用 isp
cpy isp_n prime_i
at isp_ret
go isp
if isp_ans
add prime_nop 1
out prime_i #\_
cpy prime_f prime_nop
mod prime_f 20
not prime_f
if prime_f
out #\n
eif
eif
add prime_i 1
go prime_loop
edf prime
out #input\_a\_number:
in prime_n
num prime_n
at prime_ret
go prime
2、冒泡排序
输入一个数n,再输入n个数字组成数组,冒泡排序该数组正序倒序输出。
def sort
sub n 1
cpy i 0
at loop1
grt f n i
if f
cpy j 0
at loop2
sub n i
grt f n j
add n i
if f
idx tmp1 ary j
add j 1
idx tmp2 ary j
at cmp
//这里的比较语句决定了正序还是倒序
grt f tmp1 tmp2
if f
set ary j tmp1
sub j 1
set ary j tmp2
add j 1
eif
go loop2
eif
add i 1
go loop1
eif
add n 1
add ret 1
go ret
edf sort
out #input\_n:
in n
num n
lst ary n
cpy i 0
out #input\_ n #\_numbers:\n
at loop
in x
num x
set ary i x
add i 1
grt f n i
if f
go loop
eif
out ary #\_to\_
at ret
go sort
out ary
//修改比较语句就能倒序排序
yec cmp #grt\_f\_tmp2\_tmp1
at ret
go sort
out ary