实验环境:
操作系统: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 : [ ]+ -> skip ;
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]; "); } @Override public void exitPoint(BFParser.PointContext ctx) { setBF(ctx, " cout << (char)array[ptr]; "); } @Override public void exitPlus(BFParser.PlusContext ctx) { setBF(ctx, " array[ptr] = array[ptr] + 1; "); } @Override public void exitReduce(BFParser.ReduceContext ctx) { setBF(ctx, " array[ptr] = array[ptr] - 1; "); } @Override public void exitGreat(BFParser.GreatContext ctx) { setBF(ctx, " ++ptr; "); } @Override public void exitLess(BFParser.LessContext ctx) { setBF(ctx, " --ptr; "); } @Override public void exitMiddle(BFParser.MiddleContext ctx) { // super.exitMiddle(ctx); StringBuffer buf = new StringBuffer(); buf.append(" while(array[ptr]){ "); for(BFParser.StatementContext vctx : ctx.statement()){ buf.append(" "); buf.append(getBF(vctx)); } buf.append(" } "); 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> " + "using namespace std; " + "int array[100005]; " + "int main(){ " + " int ptr = 0; "); System.out.print(cpp.BF.get(root)); System.out.print(" return 0; }"); } } /* 注意的是,在一些文法后面用”#”号定义了一个名称, 就会在用于访问生成的抽象语法树AST的访问器中生成该方法, 用于访问当这个规约被满足时候的那个树节点。 */
效果展示:
斐波那契数列程序:
HelloWorld程序: