编码尝试:使用Brainfuck实现Brainfuck解释器 - 如何写一个引导程序?

2026-04-29 08:582阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

这是一篇分帖,主帖请见:
编码尝试:使用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.直接输入与缓冲输入

未完待续

标签:软件开发