Brain-Fuck编译器

用法详见这里

___

为了防止注释中出现关键字,添加了用一对大括号表示注释的功能(注意!这不是BrainFuck语言标准所定义的!),注释范围从{开始到第一个}结尾(注释中有右大括号请用\}

如这个程序就是输入一行小写字母,并转化为大写字母输出:

,----------{判断是否为换行}[----------------------{转化成大写}.,----------]
,{延迟退出}

这个程序也是合法的:

,----------{判断是否为换行{1,2,3\}}[----------------------{转化成大写}.,----------]
{          -------这是注释---------      }
,{延迟退出}


代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<stack>
#include<vector>
using namespace std;
char *pro,*p; int len;
char **nxt,**pre;
int file_size(char* filename)
{
    FILE *fp=fopen(filename,"r");
    if(!fp) return -1;
    fseek(fp,0,SEEK_END);
    int size=ftell(fp);
    fclose(fp);
    return size;
}
void compile()
{
    nxt=new char*[len+5]; pre=new char*[len+5];
    stack<int> stk;
    for(int i=0;i<len;i++)
    {
        switch(pro[i])
        {
            case ‘[‘: stk.push(i); break;
            case ‘]‘:
                assert(stk.size());
                nxt[stk.top()]=pro+i;
                pre[i]=pro+stk.top();
                stk.pop();
                break;
            case ‘{‘:
                int pos=i++;
                while(i<len&&!(pro[i]==‘}‘&&pro[i-1]!=‘\\‘)) i++;
                assert(i<len);
                nxt[pos]=pro+i;
                break;
        }
    }
}
void run()
{
    compile();
    vector<unsigned char> mem; mem.push_back(0);
    auto it=mem.begin(); p=pro;
    while(p<pro+len)
    {
        switch(*p)
        {
            case ‘+‘: (*it)++; break;
            case ‘-‘: (*it)--; break;
            case ‘>‘:
                it++;
                if(it==mem.end()) { mem.push_back(0); it=mem.end()-1; }
                break;
            case ‘<‘:
                assert(it!=mem.begin());
                it--;
                break;
            case ‘.‘: putchar(*it); break;
            case ‘,‘: *it=getchar(); break;
            case ‘[‘:
                if(!(*it)) p=nxt[p-pro];
                break;
            case ‘]‘:
                if(*it) p=pre[p-pro];
                break;
            case ‘{‘: p=nxt[p-pro]; break;
        }
        p++;
    }
    delete[] nxt; delete[] pre;
}
int main(int argc,char** argv)
{
    if(argc==2)
    {
        char* fname=argv[1];
        len=file_size(fname);
        pro=new char[len+5]; memset(pro,0,len+5);
        FILE *fin=fopen(fname,"rb");
        fread(pro,len,1,fin);
        run();
    }
    else
    {
        const int maxn=10000000;
        pro=new char[maxn];
        while(fgets(pro,maxn,stdin))
        {
            len=strlen(pro);
            run();
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/happyZYM/p/9541634.html

时间: 2024-11-06 02:08:20

Brain-Fuck编译器的相关文章

交叉编译器 arm-linux-gnueabi 和 arm-linux-gnueabihf 的区别

  自己之前一直没搞清楚这两个交叉编译器到底有什么问题,特意google一番,总结如下,希望能帮到道上和我有同样困惑的兄弟-.. 一. 什么是ABI和EABI 1) ABI: 二进制应用程序接口(Application Binary Interface (ABI) for the ARM Architecture) 在计算机中,应用二进制接口描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口. ABI涵盖了各种细节,如: 数据类型的大小.布局和对齐; 调用约定(控制着函数的参数

Qt在Mac OS X下的编程环境搭建(配置Qt库和编译器,有图,很清楚)

尊重作者,支持原创,如需转载,请附上原地址:http://blog.csdn.net/libaineu2004/article/details/46234079 在Mac OS X下使用Qt开发,需要配置Qt库和编译器.编译器只能使用苹果公司自主研发的Clang.1.分别下载并安装XCode和Command Line Tools(必须安装),安装完毕后,Clang就有了. https://developer.apple.com/downloads/ 2.下载Qt并默认安装 http://down

编译原理第二次作业 编译器任务总结

在学习了编译原理后我开始明白编译的工作原理了,也更了解编译语言的结构.明白了编译器的编写中需要注意的各项问题,更了解了编译器的编译过程为我之后的编程提供了一些必不可少的经验,还是我的改错能力有所提高.因为写编译器使我在编程发生错误后能及时了解程序在编译过程中的原理是什么,这样我就能知道我的程序是何处的问题. 而且在学习编译原理的时候,学到了一些比较难理解的东西,通过实践不断地消化书本上的理论,最终就会有一个雏形出现.而且在编写的过程时候有一些不知道如何解决的问题时,我就会和组员讨论以得出一个可行

Lua5.0 编译器入口

编译器相关的文主要是 luac.c . 看一下它的内容: int main(int argc, char* argv[]) {  lua_State* L;  Proto* f;  int i=doargs(argc,argv);  argc-=i; argv+=i;  if (argc<=0) usage("no input files given",NULL);  L=lua_open();  luaB_opentests(L);  for (i=0; i<argc; 

C编译器剖析_1.5 结合C语言来学汇编_指针、数组和结构体

让我们再来看一份C代码,及其经UCC编译器编译后产生的主要汇编代码,如图1.33所示,其中包含了数组.指针和结构体. 图1.33 数组.指针和结构体 按照C的语义,图1.33第9行的C代码是对局部数组number的初始化,需要把number[0]初始化为2015,而数组中的其他元素皆被初始化为0.UCC编译器采取的翻译方法是:先调用memset函数来把数组number所占的内存空间清0,然后再把number[0]设为2015,如图1.33的第17至24行所示.C库函数memset的API如下所示

vi 编辑器,gcc 编译器的使用

vi编辑器是我们在linux下经常使用的文本编辑器,这个东西也是专门为程序员准备的,基本上每个Unix和Linux系统都为我们提供了这个软件,我们可以使用vi来编写我们的代码.在vi编辑器下所有操作都必须通过键盘和特定的快捷键组合来完成,刚开始学习的新手会感觉不太容易,但是这个东西很重要,我们先来学习如何使用它,掌握了这个东西去面试的时候也算是一门技能.而vim是vi的增强版,新增加了很多功能. 在shell下输入命令vi 文件名,例如:vi first.c,就开始编辑first.c文件了.vi

[Java Performance] JIT编译器简介

使用JIT(Just-In-Time)编译器 JIT编译器概览 JIT编译器是JVM的核心.它对于程序性能的影响最大. CPU只能执行汇编代码或者二进制代码,所有程序都需要被翻译成它们,然后才能被CPU执行. C++以及Fortran这类编译型语言都会通过一个静态的编译器将程序编译成CPU相关的二进制代码. PHP以及Perl这列语言则是解释型语言,只需要安装正确的解释器,它们就能运行在任何CPU之上.当程序被执行的时候,程序代码会被逐行解释并执行. 编译型语言的优缺点: 速度快:因为在编译的时

淘宝数据库OceanBase SQL编译器部分 源码阅读--生成逻辑计划

body, td { font-family: tahoma; font-size: 10pt; } 淘宝数据库OceanBase SQL编译器部分 源码阅读--生成逻辑计划 SQL编译解析三部曲分为:构建语法树,生成逻辑计划,指定物理执行计划.第一步骤,在我的上一篇博客淘宝数据库OceanBase SQL编译器部分 源码阅读--解析SQL语法树里做了介绍,这篇博客主要研究第二步,生成逻辑计划. 一. 什么是逻辑计划?我们已经知道,语法树就是一个树状的结构组织,每个节点代表一种类型的语法含义.如

[转载]arm交叉编译器gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi区别

arm交叉编译器gnueabi.none-eabi.arm-eabi.gnueabihf.gnueabi区别 (http://www.veryarm.com/296.html) 命名规则 交叉编译工具链的命名规则为:arch [-vendor] [-os] [-(gnu)eabi] arch - 体系架构,如ARM,MIPS vendor - 工具链提供商 os - 目标操作系统 eabi - 嵌入式应用二进制接口(Embedded Application Binary Interface) 根

Python环境搭建以及编译器Emacs

对于简明Python 的P13页,对shell和终端有疑问,现在来阐述两个概念: 所谓终端 终端本身是不会解析命令,它只是一个界面,是负责人机交互的一个接口.真正处理命令的并不是这些终端,真正处理命令行的是shell.终端只是负责提供一个输入命令的交互界面而已,在里面运行的命令并不归终端界面去解析,而是找到专门的命令行程序,这种程序我们一般将其称之为shell. 所谓shell shell是一个程序,一个二进制可运行可执行的程序,shell广义上可以指操作系统和用户接口的界面,图形界面也是一种s