实验环境:

  操作系统:windows 10

  JAVA:JDK 1.8

  antlr:antlr-4.7.1-complete.jar

  IDE:IntelliJ IDEA 2017.2.7


实验目的:

  实现一种语言的翻译器,将输入的源语言的程序翻译成目标语言程序。

  本次实验中用到了开源的语法分析器——anltr4,由上述的文法设计编译好文法文件,通过antlr处理.g 文件可生成对应的词法分析器和语法分析器的java文件。最终通过java文件的编写实现翻译器。


实验选题:

  源语言:BF(Brainfuck)  忽略这个名字吧...

  目标语言:C++

  测试程序:1、HelloWorld程序

       2、斐波那契数列计算

  C++与BF语法对比:

   BF是一种极小化的语言。它的表达能力较C++小很多,所以可以将所有的BF程序翻译为C++程序。对于BF语言的语法:传送门;对于C++的语法,大家就比较熟悉了。


文法设计:

  设计原则:通过代码嵌套进行分层,以代码作用进行模块划分。


具体实现:

grammar BF;

program
: statement*
; statement
: clause # symbol
| '[' statement* ']' # middle
; clause
: '+' # plus
| '-' # reduce
| '<' # less
| '>' # great
| '.' # point
| ',' # comma
; WS : [ \t\n\r]+ -> skip ;

BF.g4

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import org.antlr.v4.runtime.tree.ParseTreeWalker; import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream; class translator extends BFBaseListener{ public ParseTreeProperty<String> BF = new ParseTreeProperty<String>();
String getBF(ParseTree ctx){
return BF.get(ctx);
}
void setBF(ParseTree ctx, String s){
BF.put(ctx, s);
} @Override
public void exitComma(BFParser.CommaContext ctx) {
setBF(ctx, " cin >> array[ptr]; \n");
} @Override
public void exitPoint(BFParser.PointContext ctx) {
setBF(ctx, " cout << (char)array[ptr]; \n");
} @Override
public void exitPlus(BFParser.PlusContext ctx) {
setBF(ctx, " array[ptr] = array[ptr] + 1; \n");
} @Override
public void exitReduce(BFParser.ReduceContext ctx) {
setBF(ctx, " array[ptr] = array[ptr] - 1; \n");
} @Override
public void exitGreat(BFParser.GreatContext ctx) {
setBF(ctx, " ++ptr; \n");
} @Override
public void exitLess(BFParser.LessContext ctx) {
setBF(ctx, " --ptr; \n");
} @Override
public void exitMiddle(BFParser.MiddleContext ctx) {
// super.exitMiddle(ctx);
StringBuffer buf = new StringBuffer();
buf.append(" while(array[ptr]){ \n");
for(BFParser.StatementContext vctx : ctx.statement()){
buf.append(" ");
buf.append(getBF(vctx));
}
buf.append(" }\n");
setBF(ctx, buf.toString());
} @Override
public void exitSymbol(BFParser.SymbolContext ctx) {
//super.exitSymbol(ctx);
setBF(ctx, getBF(ctx.getChild(0)));
} @Override
public void exitProgram(BFParser.ProgramContext ctx) {
//super.exitProgram(ctx);
StringBuffer buf = new StringBuffer(); for(BFParser.StatementContext vctx : ctx.statement()){
buf.append(getBF(vctx));
}
setBF(ctx, buf.toString());
}
} public class BF2cplusplus {
public static void main(String[] args) throws IOException {
String path = "F:\\IDEA_JAVA\\BF2cplusplus\\test\\fib.bf";
CharStream inputStream = CharStreams.fromFileName(path);
BFLexer lexer = new BFLexer(inputStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
BFParser parser = new BFParser(tokenStream);
ParseTreeWalker walker = new ParseTreeWalker();
translator cpp = new translator();
ParseTree root = parser.program();
walker.walk(cpp,root); System.setOut(new PrintStream(new BufferedOutputStream(
new FileOutputStream("F:\\IDEA_JAVA\\BF2cplusplus\\test\\fib.cpp")),true));
System.out.print("#include<bits/stdc++.h>\n\n" +
"using namespace std;\n" +
"int array[100005];\n\n" +
"int main(){\n" +
" int ptr = 0;\n");
System.out.print(cpp.BF.get(root));
System.out.print(" return 0;\n}");
}
}
/*
注意的是,在一些文法后面用”#”号定义了一个名称,
就会在用于访问生成的抽象语法树AST的访问器中生成该方法,
用于访问当这个规约被满足时候的那个树节点。
*/

BF2cplusplus.java


效果展示:

斐波那契数列程序:

HelloWorld程序:

ANTLR4将BF翻译成CPP的更多相关文章

  1. ANTLR4将JSON翻译成XML

    实现功能:构建一个JSON到XML的翻译器. antlr4文件: grammar JSON; json : object | array ; object : '{' pair (',' pair)* ...

  2. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  3. 机器指令翻译成 JavaScript —— No.2 跳转处理

    上一篇,我们发现大多数 6502 指令都可以直接 1:1 翻译成 JS 代码,但除了「跳转指令」. 跳转指令,分无条件跳转.条件跳转.从另一个角度,也可分: 静态跳转:目标地址已知 动态跳转:目标地址 ...

  4. 机器指令翻译成 JavaScript —— No.3 流程分割

    上一篇 我们讨论了跳转指令,并实现「正跳转」的翻译,但最终困在「负跳转」上.而且,由于线程模型的差异,我们不能 1:1 的翻译,必须对流程进行一些改造. 当初之所以选择翻译,而不是模拟,就是出于性能考 ...

  5. 机器指令翻译成 JavaScript —— No.4 动态跳转

    上一篇,我们用模拟流程的方式,解决了跳转问题. 不过静态跳转,好歹事先是知道来龙去脉的.而动态跳转,只有运行时才知道要去哪.既然流程都是未知的,翻译从何谈起? 动态跳转,平时出现的多吗?非常多!除了 ...

  6. 机器指令翻译成 JavaScript —— No.5 指令变化

    上一篇,我们通过内置解释器的方案,解决任意跳转的问题.同时,也提到另一个问题:如果指令发生变化,又该如何应对. 指令自改 如果指令加载到 RAM 中,那就和普通数据一样,也是可以随意修改的.然而,对应 ...

  7. 机器指令翻译成 JavaScript —— No.6 深度优化

    第一篇 中我们曾提到,JavaScript 最终还得经过浏览器来解析.因此可以把一些优化工作,交给脚本引擎来完成. 现代浏览器的优化能力确实很强,但是,运行时的优化终归是有限的.如果能在事先实现,则可 ...

  8. 机器指令翻译成 JavaScript —— No.7 过渡语言

    上一篇,我们决定使用 LLVM 来优化程序,并打算用 C 作为输入语言.现在我们来研究一下,将 6502 指令转换成 C 的可行性. 跳转支持 翻译成 C 语言,可比 JS 容易多了.因为 C 支持 ...

  9. 机器指令翻译成 JavaScript —— 终极目标

    上一篇,我们顺利将 6502 指令翻译成 C 代码,并演示了一个案例. 现在,我们来完成最后的目标 -- 转换成 JavaScript. 中间码输出 我们之所以选择 C,就是为了使用 LLVM.现在来 ...

随机推荐

  1. [Python3 练习] 004 水仙花数

    题目:水仙花数 (1) 描述 水仙花数各位的数字的立方之和等于自身 如 153 为水仙花数,因为 153 = 1^3 + 5^3 + 3^3 (2) 要求 找到所有的三位数的水仙花数 (3) 程序 # ...

  2. (4.23)SQL Server中的加密

    转自:https://www.cnblogs.com/CareySon/archive/2012/04/01/SQL-SERVER-Encryption.html 简介 加密是指通过使用密钥或密码对数 ...

  3. C程序优化

    1 优化内存使用 后期程序优化的时候看内存分配是否浪费:是否留有安全裕量:有些内存是否分配过多,有些内存是否分配了没使用:尤其是创建对象的时候

  4. javascript数组排序和prototype详解

    原型的概念::原型对象里的所有属性和方法 被所有构造函数实例化出来的对象所共享,类似于java中的 static 正因为共享所以单一的操作 就会影响了全局,因此使用时需注意 基于prototype:为 ...

  5. Ubuntu 12.04安装Gitlab及问题解决

    最近看了下Git,并且之前听同学说过gitlab这个东西,就想自己也搭建一个gitlab,做一个像github那样的代码管理站点,现在的gitlab要安装确实是非常非常方便, https://abou ...

  6. IE9的兼容性

    /* 解决IE9表格错位 */ .el-table--border th:last-of-type.gutter { display: table-cell !important; width: 50 ...

  7. Spark2.0基于广播变量broadcast实现实时数据按天统计

    package com.gm.hive.SparkHive; import java.text.SimpleDateFormat; import java.util.Arrays; import ja ...

  8. 【杂记】mysql 左右连接查询中的NULL的数据筛选问题,查询NULL设置默认值,DATE_FORMAT函数

    MySQL左右连接查询中的NULL的数据筛选问题 xpression 为 Null,则 IsNull 将返回 True:否则 IsNull 将返回 False. 如果 expression 由多个变量 ...

  9. linux Sersync 参数说明

    Sersync 的可选功能是通过 xml 配置文件来实现的,下面来为大家解释该文件! 在该文件中,使用<!--中间是注释内容-->的方式去注释信息,注意不是我们平时# [root@SERS ...

  10. Linux--shell交互输入与循环语句--06

    一.交互输入 1.命令用法:read a b c   -> aa bb cc read命令同时可以定义多个变量值:而输入的内容默认以空格为分隔符,将值输入到对应的变量中:如果默认值输入过多,最后 ...