最近又玩了遍《人力资源机器》和《70亿人》(都是编程游戏,用一种类似汇编的简陋语言解决谜题,后者相当于前者的多线程版本),考虑自己设计开发一个编程游戏。游戏玩法大概是玩家管理一个机器人编队(包括近战型、远程型和支援型)与敌方机器人编队作战,每台机器人包括一个可编程CPU和一些可选模块(比如移动、撞击、射击、炮火打击和雷达模块等等),核心玩法为机器人的改装(模块装配)、编队(队伍构成、站位和对地形的利用)和编程(编写机器人CPU运行的核心代码,从模块中获取战场信息并控制模块行动)。最后打算以Unity开发,Unity学习中…
还是先用Python+pygame写个demo…
考虑到游戏内给机器人编程所使用的编程语言应该简单有效,核心操作在于CPU与模块的交互,所以刚好用上了之前设计的Y语言,不过之前的Y语言设计得非常简陋,不支持真正的函数,即使是实现一个简单的功能也需要大量语句,因此为了适应游戏内容做了一些改进些,这是前身:Y语言1.0,相比Y1.0版本主要做了以下改动:
一段代码片段示例:
Python:
# 函数flatten可以将一个多层嵌套列表list压平成一维列表
def flatten(lst):
tmp = []
for item in lst:
if isinstance(item, list):
for it in flatten(item):
tmp.append(it)
else:
tmp.append(item)
return tmp
x = [1, [2, [3, [4, [5], 6, [[7, 8], 9]]]], 10, 11, 12]
print(x, len(x))
y = flatten(x)
print(y, len(y))
翻译成Y语言:
// 函数flatten可以将一个多层嵌套列表list压平成一维列表
def flatten list
mov tmp []
mov i 0
// list[] 返回list的长度,对于非列表则返回-1
loop i < list[]
if list[i][] == -1
push tmp list[i]
else
// 激动人心的递归调用
call flatten list[i]
mov res
mov j 0
loop j < res[]
push tmp res[j]
inc j
elop
eif
inc i
elop
ret tmp
edef
// 定义复杂的嵌套列表x
mov x [1,[2,[3,[4,[5],6,[[7,8],9]]]],10,11,12]
out x x[]
call flatten x
// 返回值放入特殊变量@,此时@ = [1,2,3,4,5,6,7,8,9,10,11,12]
out @ @[]
空格是Y语言语句中唯一的分隔符,指令与变量与常量之间均以空格分隔。
语句与语句之间用换行分隔,一行只能有一条语句。
注释以//打头,运行时跳过,空行同理。
缩进对代码运行无影响。
变量名为非数字打头的下划线数字字母串,变量自身无类型,可存储Y语言支持的三种数据类型:整数,浮点数,列表。
变量分为全局变量和局部变量,取变量时优先搜索局部变量域,即定义局部变量会屏蔽同名全局变量。存变量时除非使用glb指令,否则都存入局部变量域(局部变量不存在时会被创建)。调用函数和函数返回时会发生局部变量域切换。全局变量域始终可见。
另外@为一个特殊的全局变量,用于存储一些指令的结果。
数据类型支持整数、浮点数、列表三种
数字皆以自然方式定义,如:1、0、1.5、-1.5、+6皆为有效定义;
列表以[]括起来的一组元素定义,元素间以逗号分隔,支持嵌套定义列表和包含变量,如:[1,2,3,[1,2,3],var1,var2]。空[]表示空列表。
列表的索引也采用[],list[x]表示列表list的x项,若list是多维列表也支持list[x][y]来多维索引,list[x[y]]的嵌套索引也支持。此外变量名后接空括号[]表示求长度,如array = [1,2,3] 则array[]为3,若array为非列表则array[] = -1。
Y语言的代码从头开始逐行运行,每行代码都对应一个行号,行号从0开始。每行语句的第一个单词即指令,其后都为指令需要的参数,指令指示解释器的行为,具体见下文。
指令可以分为控制指令、操作指令、逻辑指令和外部指令四类,所有指令运行时均不分大小写。其中外部指令由解释器外挂了哪些模块决定,并非通用的指令。
认真写了个解释器,应该没有没处理到的异常和BUG。
class InterpreterError(Exception):
""" 解释器内部异常 """
pass
class Interpreter:
""" Y语言解释器 """
def __init__(self, codes: list, mod_cmds: dict):
self.codes = codes # Y语言代码,字符串列表
self.ans = 0 # 特殊变量@
self.call_stack = [] # 解释器栈
self.global_vars = {} # 全局变量
self.local_vars = {} # 局部变量
self.pointer = 0 # 代码指针
self.prime_commands = {name[4:]: self.__getattribute__(name) for name in self.__dir__()
if name.startswith('cmd_')} # Y语言原生指令集
self.module_commands = mod_cmds # 模块指令集
def run(self, cpt: int):
""" 执行cpt条指令,顺利执行完毕返回True,已无指令可执行或执行出错返回False """
count = 0
while count < cpt:
if self.pointer >= len(self.codes) or self.pointer < 0:
return False
code = self.codes[self.pointer].strip()
try:
count += self.exec(code)
except InterpreterError as e:
print('(line {}: {})Cpu Error: '.format(self.pointer, code) + str(e))
return False
self.pointer += 1
return True
def exec(self, code: str):
""" 执行一条指令,执行成功返回1,否则返回0"""
cmd, *args = code.split(' ')
cmd = cmd.lower()
if not cmd or cmd.startswith('//'):
return 0
try:
self.prime_commands[cmd](args)
except KeyError:
try:
val = self.module_commands[cmd]([self.get_value(arg) for arg in args])
if val is not None:
self.set_value('@', val)
except KeyError:
raise InterpreterError('Unknow command ' + cmd)
return 1
def get_matched_end(self, ptr: int, start: str, end: str, step=1):
""" 获取ptr行strat匹配的end所在行 """
count = 1
ptr += step
while 0 <= ptr < len(self.codes):
code = self.codes[ptr].upper().strip()
if code.startswith(start):
count += 1
elif code.startswith(end):
count -= 1
if count == 0:
return ptr
ptr += step
raise InterpreterError(end + ' not found')
def get_matched_else_eif(self, ptr: int, elsed=False):
""" 获取ptr行if或else匹配的else或eif所在行 """
count = 1
ptr += 1
while ptr < len(self.codes):
code = self.codes[ptr].upper().strip()
if code.startswith('IF'):
count += 1
elif count == 1 and code.startswith('ELSE'):
if elsed:
self.pointer = ptr
raise InterpreterError('ELSE is mismatched')
return ptr
elif code.startswith('EIF'):
count -= 1
if count == 0:
return ptr
ptr += 1
raise InterpreterError('EIF not found')
def get_array_index(self, var: str):
""" 将var拆分为列表名和索引 """
left = self.left_bracket_index(var)
index = self.get_value(var[left + 1: -1])
var = self.get_value(var[: left])
if not isinstance(index, int):
raise InterpreterError(str(index) + ' is not a int')
if not isinstance(var, list):
raise InterpreterError(str(var) + ' is not a list')
return var, index
def get_operands(self, args: list):
""" 获取操作数 """
oper1 = self.get_value(args[0])
oper2 = self.get_value(args[1])
if not (isinstance(oper1, int) or isinstance(oper1, float)):
raise InterpreterError(str(oper1) + ' is not a number')
if not (isinstance(oper2, int) or isinstance(oper2, float)):
raise InterpreterError(str(oper2) + ' is not a number')
return oper1, oper2
@staticmethod
def left_bracket_index(var: str):
""" var为末尾为]的表达式,返回和末尾]匹配的[ """
left = len(var) - 2
count = 1
while left != -1:
if var[left] == '[':
count -= 1
elif var[left] == ']':
count += 1
if count == 0:
break
left -= 1
else:
raise InterpreterError(var + ' missing [')
return left
@staticmethod
def parse_list(lst: str):
""" 分析列表字符串,返回元素列表 """
items = []
count = 0
tmp = ''
for c in lst[1:-1]:
if c == '[':
count += 1
elif c == ']':
count -= 1
elif count == 0 and c == ',':
items.append(tmp)
tmp = ''
continue
tmp += c
if tmp:
items.append(tmp)
return items
@staticmethod
def return_number(var: str):
""" var为数字字符串,返回var表示的数字 """
try:
return int(var)
except ValueError:
try:
return float(var)
except ValueError:
raise InterpreterError(var + ' is not a number or identifier')
def return_var(self, var: str):
""" var为变量名,返回var的值,优先返回局部变量 """
try:
return self.local_vars[var]
except KeyError:
try:
return self.global_vars[var]
except KeyError:
raise InterpreterError(var + ' is not defined')
def get_value(self, var: str):
""" var为变量名、立即数或者数组嵌套表达式字符串,获取数组嵌套表达式的值或者变量的值或者立即数本身 """
if not var:
raise InterpreterError('invalid syntax')
if var.endswith(']'):
if var.startswith('['):
return [self.get_value(item) for item in self.parse_list(var)]
if var.endswith('[]'):
item = self.get_value(var[:-2])
if isinstance(item, list):
return len(item)
else:
return -1
var, index = self.get_array_index(var)
try:
return var[index]
except IndexError:
raise InterpreterError(str(index) + ' out of range')
if var == '@':
return self.ans
if var.isidentifier():
return self.return_var(var)
return self.return_number(var)
def set_value(self, var: str, val, global_var=False):
""" var为变量名或者数组嵌套表达式字符串,设置数组嵌套表达式的值或者变量的值为val """
if var.endswith(']'):
if var.startswith('['):
raise InterpreterError(var + ' is not a variable')
if var.endswith('[]'):
raise InterpreterError(var + ' is not a variable')
var, index = self.get_array_index(var)
try:
var[index] = val
except IndexError:
raise InterpreterError(str(index) + ' out of range')
return
if var == '@':
self.ans = val
return
if var.isidentifier():
if global_var:
self.global_vars[var] = val
else:
self.local_vars[var] = val
return
raise InterpreterError(var + ' is not a variable')
def cmp_expr(self, args: list):
""" 计算比较表达式 """
oper1 = self.get_value(args[0])
op = args[1]
oper2 = self.get_value(args[2])
if op not in {'==', '!=', '<', '<=', '>', '>='}:
raise InterpreterError(op + ' is not a cmp operator')
if not (isinstance(oper1, int) or isinstance(oper1, float)):
raise InterpreterError(str(oper1) + ' is not a number')
if not (isinstance(oper2, int) or isinstance(oper2, float)):
raise InterpreterError(str(oper2) + ' is not a number')
return eval('oper1 {} oper2'.format(op))
def cmd_at(self, args: list):
if len(args) != 1:
raise InterpreterError('AT takes 1 argument but {} were given'.format(len(args)))
self.set_value(args[0], self.pointer)
def cmd_go(self, args: list):
if len(args) != 1:
raise InterpreterError('GO takes 1 argument but {} were given'.format(len(args)))
ptr = self.get_value(args[0])
if not isinstance(ptr, int):
raise InterpreterError(str(ptr) + ' is not a int')
self.pointer = ptr
def cmd_mov(self, args: list):
if not 1 <= len(args) <= 2:
raise InterpreterError('MOV takes 1 or 2 argument(s) but {} were given'.format(len(args)))
self.set_value(args[0], self.get_value(args[1] if len(args) == 2 else '@'))
def cmd_glb(self, args: list):
if not 1 <= len(args) <= 2:
raise InterpreterError('GLB takes 1 or 2 argument(s) but {} were given'.format(len(args)))
self.set_value(args[0], self.get_value(args[1] if len(args) == 2 else '@'), global_var=True)
def cmd_if(self, args: list):
if len(args) > 1 and len(args) != 3:
raise InterpreterError('IF takes 0 or 1 or 3 argument(s) but {} were given'.format(len(args)))
if (len(args) != 3 and self.get_value(args[0] if args else '@') == 0) \
or (len(args) == 3 and not self.cmp_expr(args)):
self.pointer = self.get_matched_else_eif(self.pointer)
def cmd_else(self, args: list):
if len(args) != 0:
raise InterpreterError('ELSE takes no argument but {} were given'.format(len(args)))
self.pointer = self.get_matched_else_eif(self.pointer, elsed=True)
@staticmethod
def cmd_eif(args: list):
if len(args) != 0:
raise InterpreterError('EIF takes no argument but {} were given'.format(len(args)))
def cmd_def(self, args: list):
if len(args) < 1:
raise InterpreterError('DEF takes at least 1 argument but {} were given'.format(len(args)))
self.set_value(args[0], self.pointer, global_var=False if self.call_stack else True)
self.pointer = self.get_matched_end(self.pointer, 'DEF', 'EDEF')
def cmd_edef(self, args: list):
if len(args) != 0:
raise InterpreterError('EDEF takes no argument but {} were given'.format(len(args)))
if not self.call_stack:
raise InterpreterError('EDEF is mismatched')
self.pointer, self.local_vars = self.call_stack.pop()
def cmd_ret(self, args: list):
if len(args) > 1:
raise InterpreterError('RET takes 0 or 1 argument but {} were given'.format(len(args)))
if not self.call_stack:
raise InterpreterError('RET outside function')
if len(args) == 1:
self.set_value('@', self.get_value(args[0]))
self.pointer, self.local_vars = self.call_stack.pop()
def cmd_call(self, args: list):
if len(args) < 1:
raise InterpreterError('CALL takes at least 1 argument but {} were given'.format(len(args)))
ptr = self.get_value(args[0])
if not isinstance(ptr, int):
raise InterpreterError(args[0] + ' is not a function')
cmd, *fun_args = self.codes[ptr].strip().split(' ')
if cmd.lower() != 'def':
raise InterpreterError(args[0] + ' is not a function')
if len(args) != len(fun_args):
raise InterpreterError(
fun_args[0] + ' takes {} argument(s) but {} were given'.format(len(fun_args) - 1, len(args) - 1))
for arg in fun_args:
if not arg.isidentifier():
raise InterpreterError(arg + ' is not a variable')
self.call_stack.append((self.pointer, self.local_vars))
self.local_vars = {var: self.get_value(args[i]) for i, var in enumerate(fun_args)}
self.pointer = ptr
def cmd_loop(self, args: list):
if len(args) > 1 and len(args) != 3:
raise InterpreterError('LOOP takes 0 or 1 or 3 argument(s) but {} were given'.format(len(args)))
if (len(args) != 3 and self.get_value(args[0] if args else '@') == 0) \
or (len(args) == 3 and not self.cmp_expr(args)):
self.pointer = self.get_matched_end(self.pointer, 'LOOP', 'ELOP')
def cmd_elop(self, args: list):
if len(args) != 0:
raise InterpreterError('ELOP takes no argument but {} were given'.format(len(args)))
self.pointer = self.get_matched_end(self.pointer, 'ELOP', 'LOOP', -1) - 1
def cmd_brk(self, args: list):
if len(args) != 0:
raise InterpreterError('BRK takes no argument but {} were given'.format(len(args)))
self.pointer = self.get_matched_end(self.pointer, 'LOOP', 'ELOP')
def cmd_ctn(self, args: list):
if len(args) != 0:
raise InterpreterError('CTN takes no argument but {} were given'.format(len(args)))
self.pointer = self.get_matched_end(self.pointer, 'ELOP', 'LOOP', -1) - 1
def cmd_push(self, args: list):
if not 1 <= len(args) <= 2:
raise InterpreterError('PUSH takes 1 or 2 argument(s) but {} were given'.format(len(args)))
lst = self.get_value(args[0])
if not isinstance(lst, list):
raise InterpreterError(args[0] + ' is not a list')
lst.append(self.get_value(args[1] if len(args) == 2 else '@'))
def cmd_pop(self, args: list):
if not 1 <= len(args) <= 2:
raise InterpreterError('POP takes 1 or 2 argument(s) but {} were given'.format(len(args)))
lst = self.get_value(args[0])
if not isinstance(lst, list):
raise InterpreterError(args[0] + ' is not a list')
if len(lst) == 0:
raise InterpreterError(args[0] + ' is empty')
self.set_value(args[1] if len(args) == 2 else '@', lst.pop())
def cmd_int(self, args: list):
if len(args) != 1:
raise InterpreterError('INT takes 1 argument but {} were given'.format(len(args)))
oper = self.get_value(args[0])
if not (isinstance(oper, int) or isinstance(oper, float)):
raise InterpreterError(str(oper) + ' is not a number')
self.set_value(args[0], int(oper))
def cmd_inc(self, args: list):
if len(args) != 1:
raise InterpreterError('INC takes 1 argument but {} were given'.format(len(args)))
oper = self.get_value(args[0])
if not (isinstance(oper, int) or isinstance(oper, float)):
raise InterpreterError(str(oper) + ' is not a number')
self.set_value(args[0], oper + 1)
def cmd_dec(self, args: list):
if len(args) != 1:
raise InterpreterError('DEC takes 1 argument but {} were given'.format(len(args)))
oper = self.get_value(args[0])
if not (isinstance(oper, int) or isinstance(oper, float)):
raise InterpreterError(str(oper) + ' is not a number')
self.set_value(args[0], oper - 1)
def cmd_add(self, args: list):
if len(args) != 2:
raise InterpreterError('ADD takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', oper1 + oper2)
def cmd_sub(self, args: list):
if len(args) != 2:
raise InterpreterError('SUB takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', oper1 - oper2)
def cmd_mul(self, args: list):
if len(args) != 2:
raise InterpreterError('MUL takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', oper1 * oper2)
def cmd_div(self, args: list):
if len(args) != 2:
raise InterpreterError('DIV takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
if oper2 == 0:
raise InterpreterError('division by zero')
self.set_value('@', oper1 / oper2)
def cmd_mod(self, args: list):
if len(args) != 2:
raise InterpreterError('MOD takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
if oper2 == 0:
raise InterpreterError('modulo by zero')
self.set_value('@', oper1 % oper2)
def cmd_pow(self, args: list):
if len(args) != 2:
raise InterpreterError('POW takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', oper1 ** oper2)
def cmd_eq(self, args: list):
if len(args) != 2:
raise InterpreterError('EQ takes 2 arguments but {} were given'.format(len(args)))
oper1 = self.get_value(args[0])
oper2 = self.get_value(args[1])
self.set_value('@', 1 if oper1 == oper2 else 0)
def cmd_neq(self, args: list):
if len(args) != 2:
raise InterpreterError('NEQ takes 2 arguments but {} were given'.format(len(args)))
oper1 = self.get_value(args[0])
oper2 = self.get_value(args[1])
self.set_value('@', 1 if oper1 != oper2 else 0)
def cmd_gt(self, args: list):
if len(args) != 2:
raise InterpreterError('GT takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', 1 if oper1 > oper2 else 0)
def cmd_ls(self, args: list):
if len(args) != 2:
raise InterpreterError('LS takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', 1 if oper1 < oper2 else 0)
def cmd_ge(self, args: list):
if len(args) != 2:
raise InterpreterError('GE takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', 1 if oper1 >= oper2 else 0)
def cmd_le(self, args: list):
if len(args) != 2:
raise InterpreterError('LE takes 2 arguments but {} were given'.format(len(args)))
oper1, oper2 = self.get_operands(args)
self.set_value('@', 1 if oper1 <= oper2 else 0)
def cmd_and(self, args: list):
if len(args) != 2:
raise InterpreterError('AND takes 2 arguments but {} were given'.format(len(args)))
oper1 = self.get_value(args[0])
oper2 = self.get_value(args[1])
self.set_value('@', 1 if oper1 != 0 and oper2 != 0 else 0)
def cmd_or(self, args: list):
if len(args) != 2:
raise InterpreterError('OR takes 2 arguments but {} were given'.format(len(args)))
oper1 = self.get_value(args[0])
oper2 = self.get_value(args[1])
self.set_value('@', 1 if oper1 != 0 or oper2 != 0 else 0)
def cmd_not(self, args: list):
if len(args) != 1:
raise InterpreterError('NOT takes 1 argument but {} were given'.format(len(args)))
oper = self.get_value(args[0])
self.set_value('@', 0 if oper != 0 else 1)
class MoudleError(Exception):
""" 外部模块异常 """
pass
class BaseMoudle:
def __init__(self, command: str, level=1):
self.command = command
self.level = level
def run(self, args: list):
pass
class Inputer(BaseMoudle):
def __init__(self):
BaseMoudle.__init__(self, 'in')
def run(self, args: list):
if len(args) > 0:
raise MoudleError('IN takes no argument but {} were given'.format(len(args)))
ret = input()
try:
return int(ret)
except ValueError:
try:
return float(ret)
except ValueError:
raise MoudleError(ret + ' is not a number')
class Outputer(BaseMoudle):
def __init__(self):
BaseMoudle.__init__(self, 'out')
def run(self, args: list):
print(*args)
from moudle import BaseMoudle
from interpreter import Interpreter
class Cpu:
def __init__(self, command_per_turn: int):
self.cpt = command_per_turn
self.bus = Bus()
self.interpreter = None
def boot(self, codestr: str):
codes = codestr.split('\n')
mod_cmds = {mod.command: mod.run for mod in self.bus.modules.values()}
self.interpreter = Interpreter(codes, mod_cmds)
def run(self):
return self.interpreter.run(self.cpt)
class Bus:
def __init__(self):
self.modules = {}
def install(self, moudle: BaseMoudle):
if moudle.command in self.modules.keys():
raise RuntimeError('Moudle Access Conflict: ' + moudle.command)
self.modules[moudle.command] = moudle
def uninstall(self, moudle: BaseMoudle):
if moudle.command in self.modules.keys():
del self.modules[moudle.command]
raise RuntimeError('Moudle Access Not Existent: ' + moudle.command)
from cpu import Cpu
from moudle import Inputer, Outputer
code = '''
// 函数flatten可以将一个多层嵌套列表list压平成一维列表
def flatten list
mov tmp []
mov i 0
// list[] 返回list的长度,对于非列表则返回-1
loop i < list[]
if list[i][] == -1
push tmp list[i]
else
// 激动人心的递归调用
call flatten list[i]
mov res
mov j 0
loop j < res[]
push tmp res[j]
inc j
elop
eif
inc i
elop
ret tmp
edef
// 定义复杂的嵌套列表x
mov x [1,[2,[3,[4,[5],6,[[7,8],9]]]],10,11,12]
out x x[]
call flatten x
// 返回值放入特殊变量@,此时@ = [1,2,3,4,5,6,7,8,9,10,11,12]
out @ @[]
'''
cpu = Cpu(1)
cpu.bus.install(Inputer())
cpu.bus.install(Outputer())
cpu.boot(code)
count = 1
while cpu.run():
count += 1
print('\ncount: {}'.format(count))
def isprime n
pow n 0.5
mov t
mov i 2
loop i <= t
mod n i
if @ == 0
ret 0
eif
inc i
elop
ret 1
edef
def print_prime n
mov primes []
mov i 2
loop i <= n
call isprime i
if
push primes i
eif
inc i
elop
ret primes
edef
call print_prime 1000
out @
输出:[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
def Qsort array
sub array[] 1
call quick_sort array 0 @
edef
def quick_sort array low high
loop low < high
mov i low
mov j high
mov key array[low]
loop i < j
loop key <= array[j]
if i >= j
brk
eif
dec j
elop
mov array[i] array[j]
loop key >= array[i]
if i >= j
brk
eif
inc i
elop
mov array[j] array[i]
elop
mov array[i] key
sub i 1
call quick_sort array low @
add i 1
mov low
elop
edef
mov array [3,5,6,8,3,1,2,5,7,9,5,6,8,6,5]
call Qsort array
out array
输出:[1, 2, 3, 3, 5, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9]