编码尝试:使用Brainfuck实现Brainfuck解释器 - 如何写一个引导程序?
- 内容介绍
- 文章标签
- 相关推荐
这是一篇分帖,主帖请见:
编码尝试:使用Brainfuck实现Brainfuck解释器 - 开发调优 - LINUX DO
前水言
终于从无穷无尽的ddl里面解脱出70%了,能有点时间继续写了!
先来给佬u们贴个成果截图:
自举自举自
f22f83f7a96966ab19835b47de6579ea2021×1006 188 KB
总共套了4层:
最外层是 @so1ve 开发的BrainFrost。(BF→x86-64机器码编译器)
第二层是以16777216位长,16栈深构建的解释器。
第三层是以480位长,16栈深构建的解释器。
第四层是一个小小的echo程序。
太爽辣! >w<
好了,说回正文:Boot
主帖中说到,这个Boot需要这些功能:
- 读取指令直到指令终止符。
- 重新编码指令以加速后面的运行。
- 将指令逆序写入
.text段。 - 这一条是什么,滚木吗?
我们来分析一下实现:
- 逆序写入是最简单的,只需要确保每一次有效输入之后会多执行一个
<,我们就能左移一格。 - 主循环,稍难一点,它会一直执行直到读取到我们规定的终止符
~。 - 一个巨大的类switch结构,这个最难,它负责识别不同的指令,并执行对应的逻辑。
- 一个重编码指令的逻辑,这玩意超级考验设计。
1. 内存分配
首先,我们需要一大堆的>,用来把指针移动到整个程序段的最右边,这些>的个数就是解释器程序段的大小。
按理说,有这么大就够了,但很显然,指针向左移动,意味着指针右边是写好的数据,而boot是有逻辑需要运行的,少不了临时变量,所以我们很自然地要把临时变量放在左边还没有写入的空白处。
问题来了,假如我们有16384格程序段,boot运行时的临时变量占用为n,那么当指针写完从左往右的第n+1格之后,再向左移动时,临时变量区就会撞墙,程序就炸了。
所以,在分配完所有程序段之后,我们还需要向右移动额外的n格。
第一段我们就写好了,像这样(假设我们有32指令段大小,并且boot需要占用8格临时变量)
>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> 程序段
>>>>>>>> 临时变量
2. 主循环
当我们移动到起点之后,我们就需要开启我们的主循环。
在brainfuck中,循环是依赖于0和非0的,我们必须要用数值来控制我们的循环。但很显然,这个循环长度我们预先不知道,所以我们需要使用状态变量来控制整个循环。只要状态变量非0,循环就会进行下去。在我们boot的逻辑中,循环只会执行一次,不妨一开始就把状态变量设为非0,然后在读到终止符的时候置0,这样循环就结束了。
状态变量的非0值,其实用多少都行,不过为了迁移(我们是需要逐渐把整个临时变量区左移的)的时候快速移动,这个数字距离0越近越好,所以我们可以使用1或者255。这里,我采用了1作为这个值。每轮循环结束时,我们都需要左移这个量。
然后,要进入循环,则循环之前我们需要把指针指到状态变量,一轮循环结束后,为了继续/跳出循环,我们也需要把指针移回状态变量。
我们据此可以写一个永远向左直到撞墙炸掉的循环:
我们假定指针最开始指在程序段的待写位,而待写位的左8位是循环控制位
{控}{ }{ }{ }{ }{ }{ }{ }{写}
^^指针初始位置
<<<<<<<<<+ 移动到控制位,并置非0
[ 主循环
[-<+>] 移动当前控制位到当前控制位的左1位
< 把指针移动到新控制位
]
我们就做出了一个永远向左移动的循环。
3.直接输入与缓冲输入
未完待续
网友解答:--【壹】--:
这是一篇分帖,主帖请见:
编码尝试:使用Brainfuck实现Brainfuck解释器 - 开发调优 - LINUX DO
前水言
终于从无穷无尽的ddl里面解脱出70%了,能有点时间继续写了!
先来给佬u们贴个成果截图:
自举自举自
f22f83f7a96966ab19835b47de6579ea2021×1006 188 KB
总共套了4层:
最外层是 @so1ve 开发的BrainFrost。(BF→x86-64机器码编译器)
第二层是以16777216位长,16栈深构建的解释器。
第三层是以480位长,16栈深构建的解释器。
第四层是一个小小的echo程序。
太爽辣! >w<
好了,说回正文:Boot
主帖中说到,这个Boot需要这些功能:
- 读取指令直到指令终止符。
- 重新编码指令以加速后面的运行。
- 将指令逆序写入
.text段。 - 这一条是什么,滚木吗?
我们来分析一下实现:
- 逆序写入是最简单的,只需要确保每一次有效输入之后会多执行一个
<,我们就能左移一格。 - 主循环,稍难一点,它会一直执行直到读取到我们规定的终止符
~。 - 一个巨大的类switch结构,这个最难,它负责识别不同的指令,并执行对应的逻辑。
- 一个重编码指令的逻辑,这玩意超级考验设计。
1. 内存分配
首先,我们需要一大堆的>,用来把指针移动到整个程序段的最右边,这些>的个数就是解释器程序段的大小。
按理说,有这么大就够了,但很显然,指针向左移动,意味着指针右边是写好的数据,而boot是有逻辑需要运行的,少不了临时变量,所以我们很自然地要把临时变量放在左边还没有写入的空白处。
问题来了,假如我们有16384格程序段,boot运行时的临时变量占用为n,那么当指针写完从左往右的第n+1格之后,再向左移动时,临时变量区就会撞墙,程序就炸了。
所以,在分配完所有程序段之后,我们还需要向右移动额外的n格。
第一段我们就写好了,像这样(假设我们有32指令段大小,并且boot需要占用8格临时变量)
>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> 程序段
>>>>>>>> 临时变量
2. 主循环
当我们移动到起点之后,我们就需要开启我们的主循环。
在brainfuck中,循环是依赖于0和非0的,我们必须要用数值来控制我们的循环。但很显然,这个循环长度我们预先不知道,所以我们需要使用状态变量来控制整个循环。只要状态变量非0,循环就会进行下去。在我们boot的逻辑中,循环只会执行一次,不妨一开始就把状态变量设为非0,然后在读到终止符的时候置0,这样循环就结束了。
状态变量的非0值,其实用多少都行,不过为了迁移(我们是需要逐渐把整个临时变量区左移的)的时候快速移动,这个数字距离0越近越好,所以我们可以使用1或者255。这里,我采用了1作为这个值。每轮循环结束时,我们都需要左移这个量。
然后,要进入循环,则循环之前我们需要把指针指到状态变量,一轮循环结束后,为了继续/跳出循环,我们也需要把指针移回状态变量。
我们据此可以写一个永远向左直到撞墙炸掉的循环:
我们假定指针最开始指在程序段的待写位,而待写位的左8位是循环控制位
{控}{ }{ }{ }{ }{ }{ }{ }{写}
^^指针初始位置
<<<<<<<<<+ 移动到控制位,并置非0
[ 主循环
[-<+>] 移动当前控制位到当前控制位的左1位
< 把指针移动到新控制位
]
我们就做出了一个永远向左移动的循环。
3.直接输入与缓冲输入
未完待续
这是一篇分帖,主帖请见:
编码尝试:使用Brainfuck实现Brainfuck解释器 - 开发调优 - LINUX DO
前水言
终于从无穷无尽的ddl里面解脱出70%了,能有点时间继续写了!
先来给佬u们贴个成果截图:
自举自举自
f22f83f7a96966ab19835b47de6579ea2021×1006 188 KB
总共套了4层:
最外层是 @so1ve 开发的BrainFrost。(BF→x86-64机器码编译器)
第二层是以16777216位长,16栈深构建的解释器。
第三层是以480位长,16栈深构建的解释器。
第四层是一个小小的echo程序。
太爽辣! >w<
好了,说回正文:Boot
主帖中说到,这个Boot需要这些功能:
- 读取指令直到指令终止符。
- 重新编码指令以加速后面的运行。
- 将指令逆序写入
.text段。 - 这一条是什么,滚木吗?
我们来分析一下实现:
- 逆序写入是最简单的,只需要确保每一次有效输入之后会多执行一个
<,我们就能左移一格。 - 主循环,稍难一点,它会一直执行直到读取到我们规定的终止符
~。 - 一个巨大的类switch结构,这个最难,它负责识别不同的指令,并执行对应的逻辑。
- 一个重编码指令的逻辑,这玩意超级考验设计。
1. 内存分配
首先,我们需要一大堆的>,用来把指针移动到整个程序段的最右边,这些>的个数就是解释器程序段的大小。
按理说,有这么大就够了,但很显然,指针向左移动,意味着指针右边是写好的数据,而boot是有逻辑需要运行的,少不了临时变量,所以我们很自然地要把临时变量放在左边还没有写入的空白处。
问题来了,假如我们有16384格程序段,boot运行时的临时变量占用为n,那么当指针写完从左往右的第n+1格之后,再向左移动时,临时变量区就会撞墙,程序就炸了。
所以,在分配完所有程序段之后,我们还需要向右移动额外的n格。
第一段我们就写好了,像这样(假设我们有32指令段大小,并且boot需要占用8格临时变量)
>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> 程序段
>>>>>>>> 临时变量
2. 主循环
当我们移动到起点之后,我们就需要开启我们的主循环。
在brainfuck中,循环是依赖于0和非0的,我们必须要用数值来控制我们的循环。但很显然,这个循环长度我们预先不知道,所以我们需要使用状态变量来控制整个循环。只要状态变量非0,循环就会进行下去。在我们boot的逻辑中,循环只会执行一次,不妨一开始就把状态变量设为非0,然后在读到终止符的时候置0,这样循环就结束了。
状态变量的非0值,其实用多少都行,不过为了迁移(我们是需要逐渐把整个临时变量区左移的)的时候快速移动,这个数字距离0越近越好,所以我们可以使用1或者255。这里,我采用了1作为这个值。每轮循环结束时,我们都需要左移这个量。
然后,要进入循环,则循环之前我们需要把指针指到状态变量,一轮循环结束后,为了继续/跳出循环,我们也需要把指针移回状态变量。
我们据此可以写一个永远向左直到撞墙炸掉的循环:
我们假定指针最开始指在程序段的待写位,而待写位的左8位是循环控制位
{控}{ }{ }{ }{ }{ }{ }{ }{写}
^^指针初始位置
<<<<<<<<<+ 移动到控制位,并置非0
[ 主循环
[-<+>] 移动当前控制位到当前控制位的左1位
< 把指针移动到新控制位
]
我们就做出了一个永远向左移动的循环。
3.直接输入与缓冲输入
未完待续
网友解答:--【壹】--:
这是一篇分帖,主帖请见:
编码尝试:使用Brainfuck实现Brainfuck解释器 - 开发调优 - LINUX DO
前水言
终于从无穷无尽的ddl里面解脱出70%了,能有点时间继续写了!
先来给佬u们贴个成果截图:
自举自举自
f22f83f7a96966ab19835b47de6579ea2021×1006 188 KB
总共套了4层:
最外层是 @so1ve 开发的BrainFrost。(BF→x86-64机器码编译器)
第二层是以16777216位长,16栈深构建的解释器。
第三层是以480位长,16栈深构建的解释器。
第四层是一个小小的echo程序。
太爽辣! >w<
好了,说回正文:Boot
主帖中说到,这个Boot需要这些功能:
- 读取指令直到指令终止符。
- 重新编码指令以加速后面的运行。
- 将指令逆序写入
.text段。 - 这一条是什么,滚木吗?
我们来分析一下实现:
- 逆序写入是最简单的,只需要确保每一次有效输入之后会多执行一个
<,我们就能左移一格。 - 主循环,稍难一点,它会一直执行直到读取到我们规定的终止符
~。 - 一个巨大的类switch结构,这个最难,它负责识别不同的指令,并执行对应的逻辑。
- 一个重编码指令的逻辑,这玩意超级考验设计。
1. 内存分配
首先,我们需要一大堆的>,用来把指针移动到整个程序段的最右边,这些>的个数就是解释器程序段的大小。
按理说,有这么大就够了,但很显然,指针向左移动,意味着指针右边是写好的数据,而boot是有逻辑需要运行的,少不了临时变量,所以我们很自然地要把临时变量放在左边还没有写入的空白处。
问题来了,假如我们有16384格程序段,boot运行时的临时变量占用为n,那么当指针写完从左往右的第n+1格之后,再向左移动时,临时变量区就会撞墙,程序就炸了。
所以,在分配完所有程序段之后,我们还需要向右移动额外的n格。
第一段我们就写好了,像这样(假设我们有32指令段大小,并且boot需要占用8格临时变量)
>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> 程序段
>>>>>>>> 临时变量
2. 主循环
当我们移动到起点之后,我们就需要开启我们的主循环。
在brainfuck中,循环是依赖于0和非0的,我们必须要用数值来控制我们的循环。但很显然,这个循环长度我们预先不知道,所以我们需要使用状态变量来控制整个循环。只要状态变量非0,循环就会进行下去。在我们boot的逻辑中,循环只会执行一次,不妨一开始就把状态变量设为非0,然后在读到终止符的时候置0,这样循环就结束了。
状态变量的非0值,其实用多少都行,不过为了迁移(我们是需要逐渐把整个临时变量区左移的)的时候快速移动,这个数字距离0越近越好,所以我们可以使用1或者255。这里,我采用了1作为这个值。每轮循环结束时,我们都需要左移这个量。
然后,要进入循环,则循环之前我们需要把指针指到状态变量,一轮循环结束后,为了继续/跳出循环,我们也需要把指针移回状态变量。
我们据此可以写一个永远向左直到撞墙炸掉的循环:
我们假定指针最开始指在程序段的待写位,而待写位的左8位是循环控制位
{控}{ }{ }{ }{ }{ }{ }{ }{写}
^^指针初始位置
<<<<<<<<<+ 移动到控制位,并置非0
[ 主循环
[-<+>] 移动当前控制位到当前控制位的左1位
< 把指针移动到新控制位
]
我们就做出了一个永远向左移动的循环。
3.直接输入与缓冲输入
未完待续

