用c++创造编译器(Brainfuck)

2023-11-06

目录

初始化

主算法

思路​​​​​​​

完整代码

补充


请先看此文章

大家了解之后,可能会想:这么简单的语言,能不能用代码写出一个Brainfuck呢?

哈哈,当然可以!作为第一次发布文章的博主,就来帮帮你吧!

初始化:

#include <iostream>
#include <fstream>
#include <string>
//范围越大,能存放的数就越多,如果要存放很多数,就要把范围设得大一些
#define width 100000
//读入字符
std::string str;
//存放指针对应的数字和指针
int f[width], p = width / 2;
//要先把要编译的Brainfuck代码放入Brainfuck.txt
std::ifstream is ("Brainfuck.txt");

int main ()
{
	//主算法……
	return 0;
}

主算法:

先来一个while读入字符,在一个一个遍历str里的字符,最后判断每一个字符是什么

while (is >> str)
{
	for (int i = 0; i < str.size (); ++i)
	{
		switch (str[i])
		{
			case '>': ++p; break;
			case '<': --p; break;
			case '+': ++f[p]; break;
			case '-': --f[p]; break;
			case '.': printf ("%c", f[p]); break;
			case ',': f[p] = getchar(); break;	
			default: break;//可以不加,让大家看得清晰点
		}
	}
}

前面六个运算符都很简单,但最后的循环运算符[ ]就比较难了

思路:

因为再程序确保无误的情况下,[ 肯定是先出现的,那我们再在判断字符是不是"[",如果是,那就调用loop函数

在loop函数中,需要输入一个实参:指针,告诉函数要从哪里开始便历

case '[' : loop (i + 1); break;

loop函数的遍历和刚才的遍历差不多,不过在循环的过程中,需要检测每个字符是不是"]",如果是,再判断指针对应的数值是否为0,是那就退出函数,不是就继续循环 

void loop(int pp)
{
	int i;
	for (i = pp; str[i] != ']'; ++i)
	{
		switch (str[i])
		{
			case '>': ++p; break;
			case '<': --p; break;
			case '+': ++f[p]; break;
			case '-': --f[p]; break;
			case '.': printf("%c", f[p]); break;
			case ',': loop(i + 1); break;	
		}			
	}
	
	if (f[p] != 0)
	{
		loop(pp);
	}
}

​

注意!

如果str被遍历完了,就要在读入str,要不然程序会出现错误

void loop(int pp)
{
	int i;
	for (i = pp; str[i] != ']'; ++i)
	{
		if (i == str.size ())
		{
			is >> str;
			i = 0;
		}
		
		switch (str[i])
		{
			case '>': ++p; break;
			case '<': --p; break;
			case '+': ++f[p]; break;
			case '-': --f[p]; break;
			case '.': printf("%c", f[p]); break;
			case ',': f[p] = getchar(); break;	
			case '[': loop(i + 1); break;	
		}			
	}
	
	if (f[p] != 0)
	{
		loop(pp);
	}
}

​

这个程序还有一个漏洞,那就是当函数调用完之后,指针还指着"["的下一个,所以还得在修改一下

int loop(int pp)
{
	int i;
	for (i = pp; str[i] != ']'; ++i)
	{
		if (i == str.size ())
		{
			is >> str;
			i = 0;
		}
		
		switch (str[i])
		{
			case '>': ++p; break;
			case '<': --p; break;
			case '+': ++f[p]; break;
			case '-': --f[p]; break;
			case '.': printf("%c", f[p]); break;
			case ',': f[p] = getchar(); break;	
			case '[': i = loop(i + 1); break;	
		}			
	}
	
	if (f[p] != 0)
	{
		loop(pp);
	}
	
	return i;
}

完整代码:

#include <iostream>
#include <fstream>
#include <string>
#define width 100000
std::string str;
int f[width], p = width / 2;
std::ifstream is ("Brainfuck.txt");

int loop(int pp)
{
	int i;
	for (i = pp; str[i] != ']'; ++i)
	{
		if (i == str.size ())
		{
			is >> str;
			i = 0;
		}
		
		switch (str[i])
		{
			case '>': ++p; break;
			case '<': --p; break;
			case '+': ++f[p]; break;
			case '-': --f[p]; break;
			case '.': printf("%c", f[p]); break;
			case ',': f[p] = getchar(); break;	
			case '[': i = loop(i + 1); break;	
		}			
	}
	
	if (f[p] != 0)
	{
		loop(pp);
	}
	
	return i;
}

int main ()
{
	while (is >> str)
	{
		for (int i = 0; i < str.size (); ++i)
		{
			switch (str[i])
			{
				case '>': ++p; break;
				case '<': --p; break;
				case '+': ++f[p]; break;
				case '-': --f[p]; break;
				case '.': printf ("%c", f[p]); break;
				case ',': f[p] = getchar(); break;	
				case '[': i = loop(i + 1); break;		
				default: break;
			}
		}
	}
	return 0;
}

补充

我们还可以做一个程序:输入字符串,然后程序就会将字符串转为“Brainfuck”语言,存放在“Brainfuck.txt”里

程序如下

#include <iostream>
#include <fstream>

std::ofstream os ("Brainfuck.txt");
std::string str = "Hello, world";

void print (char ch)
{
	for (int i = 1; i <= ch; ++i)
	{
		os << '+';
	}
	os << ".>" << std::endl;
}

int main ()
{
	std::cin >> str;
	for (char ch : str)
	{
		print (ch);
	}
	return 0;
}

完结

作者是首次发布文章,如文章有问题请小喷~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用c++创造编译器(Brainfuck) 的相关文章

随机推荐

  • 4.7 期货每日早盘操作建议

    期货期权日评 静待反抽 PMI数据显示国内疫情基本控制后复工已较明显 经济数据将在二季度逐步改善 同时近期高层在贷款 汽车消费方面政策频出 有望支持实体经济复苏 当前A股已处于低位 期指继续做空的风险收益比在下降 因此建议可在股指期权上轻仓
  • Failed to execute ‘addColorStop‘ on ‘CanvasGradient‘: The value provided (‘undefined‘) could not be

    在echarts使用属性visualMap对折线图进行区间的变色设置 结果写完直接报错 Uncaught DOMException Failed to execute addColorStop on CanvasGradient The v
  • springboottest注解

    SpringBoot test 好习惯要坚持下去 CSDN博客 springboot test springboot使用 SpringBootTest注解进行单元测试 灰太狼 CSDN博客 springboot test
  • 如何为模型不同层设置不同的学习率?

    在模型调参中常用的一种方法是针对不同层设置不同的学习率 以此避免因难易程度不一致引起的过拟合等问题 一 模型举例 class Model nn Module def init self input size hidden size outp
  • 【cfengDB】自己实现数据库第0节 ---整体介绍及事务管理层实现

    LearnProj 内容管理 MySQL系统结构 一条SQL执行流程 cfengDB整体结构 事务管理TM模块 TID文件规则定义 文件读写 NIO RandomAccessFile FileChannel ByteBuffer 接口实现
  • 【单调栈】找到左右两边的最近小于元素

    基本概念 从一个问题引出单调栈的这个概念 给定一个数组 对于数组中的每一个元素 分别找到它左边和右边最近的小于它的元素 无重复数组 默认该数组中的元素是无重复的 我们可以维护一个栈 从栈的下方到上方 元素的大小从小到大 对于数组中的每一个元
  • OSI参考模型与TCP/IP参考模型(计算机网络)

    一 1 OSI参考模型有7层 从上到下为 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 如下图1 2 TCP IP参考模型有4层 自上到下分别为 应用层 传输层 网际层 网络接口层 如下图2 3 常考的5层参考模型是这样的 自
  • 微信小程序生成分享带参数二维码图片 并添加文字功能

    笔者最近接到一个新的任务 不是很难的功能 就是之前没有接触过 后端生成带参数的小程序二维码图片 并在图片下面添加一些文字 想在将代码分享给大家 期望可以给大家提供帮助 一 首先生成小程序的分享二维码有三种方式 接口 A 适用于需要的码数量较
  • 编程报错和问题解决办法【总结篇】

    目录 1 VMware开启虚拟机失败 模块 Disk 启动失败 2 vim 输入时光标键会变成a b c d 3 vim中delete backspace 键不能向左删除 4 conda command not found解决办法 5 进入
  • Leaflet的Vue组件 — Vue2Leaflet

    原文地址 Leaflet的Vue组件 Vue2Leaflet 这两天折腾Vue 在GitHub上发现了一个开源项目Vue2Leaflet Vue2Leaflet是一个Vue框架的JavaScript库 封装了Leaflet 它使构建地图变得
  • element Tree树形控件使用记录

    需求为使用弹窗选择区域 弹窗左侧为待选区 右侧会展示当前已选中项 也是树形控件展示 如果打开弹窗时上次有选中数据 需要展示出来并勾选相应树形节点 1 html及配置项 数据源部分 由于需求中有需要主动设置选中项 所以需要设置node key
  • 【Linux】线程池

    目录 前言 线程池概念 线程池的实现 前言 这篇文章来实现一个线程池 线程池概念 线程池 一种线程使用模式 线程过多会带来调度开销 进而影响缓存局部性和整体性能 而线程池维护着多个线程 等待着监督管理者分配可并发执行的任务 这避免了在处理短
  • Linux_基础知识笔记4

    基础知识 一 Linux目录结构 二 cat 查看文件内容 三 more 查看文件内容 内容多 四 less 查看文件内容 五 head tail 查看文件内容 六 wc 统计文件内容 七 grep 检索和过滤文件内容 八 gzip bzi
  • 利用闭包,在不设置全局变量的情况下,完成再次点击退出功能

    做APP经常会用到的功能就是 第一次点击弹出退出提示 再次点击退出app 以前常规做法 就是立flag 代码如下 var ableToOut null api addEventListener name keyback function r
  • 关于Undefined symbols for architecture x86_64这个错的总结

    最近在Mac上做一个程序 需要调用动态链接库 出现两次Undefined symbols for architecture x86 64的错误 所以总结下 第一个是 Undefined symbols for architecture x8
  • C++ 复制(拷贝)构造函数

    复制构造函数的定义 复制构造函数是一种特殊的构造函数 其形参为本类的对象引用 作用是用一个已经存在的对象去初始化同类型的新对象 复制构造函数被调用的三种情况 1 定义了一个对象 以本类另一个对象作为初始值 发生复制构造 2 如果函数的形参是
  • matlab中input输入多个数_基于MATLAB的PID控制算法仿真

    一 初学者学习目的 1 利用Matlab Simulink实现PID控制算法 2 观察不同PID参数对控制性能的影响 3 掌握PID参数整定的方法 二 实践内容 1 以二阶系统 为被控对象 K 135 在阶跃输入信号的作用下 用simuli
  • keil添加了头文件仍然报找不到头文件的原因

    1 如果工程中有中文路径 keil是无法识别中文路径的 需要修改为英文路径 2 如果工程中的路径存在数字开头 则keil无法识别该路径 需要修改为以英文字符开头 3 如果修改了工程中的文件夹名 则需要重新将文件夹包含到工程中 4 点击魔术棒
  • Datax插件二次开发之HdfsWriter支持parquet

    Datax插件二次开发之HdfsWriter支持parquet Date December 24 2021 1 背景 目前 公司的OLAP和AD HOC组件主要使用impala 而当前我们的impala版本支持parquet textfil
  • 用c++创造编译器(Brainfuck)

    目录 初始化 主算法 思路 完整代码 补充 请先看此文章 大家了解之后 可能会想 这么简单的语言 能不能用代码写出一个Brainfuck呢 哈哈 当然可以 作为第一次发布文章的博主 就来帮帮你吧 初始化 include