娱乐向、Y语言、Python——设计一门简单的解释型编程语言并实现解释器

简介

突发奇想地想设计一门编程语言,但又没学过编译原理只能整个解释型语言了,又一想符号计算也很麻烦,干脆整个汇编一样的语言算了,当然还得是有与众不同特点的语言,那就是代码运行的时候可以修改自身代码的语言。最后,名字就叫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

效果

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值