文档章节

25行代码实现一个简单的编译器

obaniu
 obaniu
发布于 2017/11/06 14:40
字数 853
阅读 220
收藏 2

起因


25行JavaScript语句实现一个简单的编译器》实现的是一个简单到不能再简单的玩具的玩具,他的魔法是函数式编程简化了js代码。java 8提供了函数式编程的支持,昨晚脑子抽风突然兴趣java也可以实现一个如此简单的编译器!

java和js语言差异
    

    java相对js这类胶水语言来说还是相对啰嗦的,一些动态语言的特性在java里并不具备。《25行JavaScript语句实现一个简单的编译器》的作者是个js高手js用得溜溜的,下面说说他用到js里有而java没有的功能。

  1. js 字符串模板
    他在Transpiler中使用ES2015新增的模板字符串功能。

     `(${ast.expr.map(transpileNode).join(' ' + opMap[ast.val] + ' ')})`;

     

  2. js内置 map和简单的赋值语法

    const node = { val: consume(), type: Op, expr: [] };

    其他胶水语言的话对应的是tuple,java要实现的话还真啰嗦不少。
     

  3. 模式匹配(实际这是js的map啊啊啊)

      const opAcMap = {
        'sum': args => args.reduce((a, b) => a + b, 0),
        'sub': args => args.reduce((a, b) => a - b),
        'div': args => args.reduce((a, b) => a / b),
        'mul': args => args.reduce((a, b) => a * b, 1)
      };

    java还木有模式匹配。
    没有这几个js功能,但我们还是可以通过各种方法绕一下的。怎么绕?请看下文!

 

java实现

废话不啰嗦上代码,代码风格学他的也紧促点凑合着看吧!

	static final int OP = 0, NUM = 1;
	private static List<String> lexer(String input){return  Stream.of(input.split(" ")).map(String::trim).filter(s -> s.length() > 0).collect(Collectors.toList());}
	private static class Parser {
		Iterator<String> lex;
		String next=null;
		public Parser(List<String> lex) { this.lex=lex.iterator();  }
		private Node parseOp(String str) {
			Node n = new Node(str, OP);
			while (lex.hasNext())	n.addLast(parse());
			return n;
		}
		public Node parse() { return (next=lex.next()).matches("\\d+") ? new Node(Integer.parseInt(next), NUM) : parseOp(next); }
	}
	final static Map<String, String> opMap = new HashMap<String, String>(4) {{ put("sum", "+"); put("sub", "-"); put("div", "/"); put("mul", "*");}};
	private static String codeGenerator (Node ast) { return ast.type == NUM ? String.valueOf(ast.val) : genOp(ast); }
	private static String genOp(Node node) { return "(" + node.stream().map(n -> codeGenerator(n)) .collect(Collectors.joining(" " + opMap.get(node.val) + " ")) + ")"; }
	private static class Node  extends ArrayDeque<Node>{
		Object val; 
		int type;
		public Node(Object val, int type) {
			super();
			this.val = val;
			this.type = type;
		}
	}
	private static int eval(Node ast) { return (int) (ast.type == NUM ? ast.val : ast.stream().reduce(evalOps.get(ast.val)).get().val); }
	final static Map<String,BinaryOperator<Node>> evalOps=new HashMap<String,BinaryOperator<Node>>(4) {{
		put("sum", (a, b) -> new Node(eval(a) + eval(b), NUM)); put("sub", (a, b) -> new Node(eval(a) - eval(b), NUM));
		put("div", (a, b) -> new Node(eval(a) / eval(b), NUM)); put("mul", (a, b) -> new Node(eval(a) * eval(b), NUM));}};

js实现lex和transpile用了23行代码。没有tuple java实现node多花了9行代码,加起来用了25行。不过他加eval功能的代码行(33行)比我这(29行)可是多的。代码行数多少是其次,函数式编程写代码还真精简不少,写的爽看得也不累。

写在后

最后还是想说这个玩具的玩具。之所以说这个是玩具呢。
首先,他定的语法规则是非常简单的。
其次,表面是一个乘除加减语言,但是没有算术优先级。
最后,这跟什么编译器没啥多大的关联(词法分析器用空格直接分割也只能是玩泥沙),如果想写个简单解析器之类的可以参考我的《练手写了个SQLite解析器》和《一个android sqlite CRUD代码生成小工具
本文源码下载移步github《tiny-compiler-java

© 著作权归作者所有

obaniu
粉丝 37
博文 83
码字总数 39241
作品 0
广州
高级程序员
私信 提问
通过DLS解析器,了解JS的编译原理

接触Javascript很长一段时间了,但一直浮在语言的表面,今天决定重头开始更深入的学习Javascript,先从Javascript的编译原理开始。 在程序的执行方式中有编译型和解释型,以前学习的C语言就是...

tryzf
2018/06/30
0
0
使用JS实现JS编译器,并将目标js生成二进制

上一篇文章 利用LLVM实现JS的编译器,创造属于自己的语言 中讲到使用llvm用C实现JS编译器,本片文章将使用JS来实现JS编译器,还是应了《Atwood定律》能够使用JavaScript实现的,必将使用Jav...

zy445566
2018/09/11
0
0
reactjs开发自制编程语言编译器:实现变量绑定和函数调用

在编程时,我们会初始化一个变量,给变量赋初值,例如下面语句: 上面代码被编译器解读后,变量x就会和数值25绑定在一起。下次使用到变量x时,编译器会读取它绑定的值,然后用于相关代码的执...

望月从良
2018/05/18
0
0
什么是编程?什么是软件开发?

在学校里,为了实现课堂练习,为了完成作业,为了实现而实现的代码过程,我将其定义为编程,这个时候,你只要正确的让编译器把你的代码顺利的编译通过,输出你希望的或者说你的导师希望的结果...

彭博
2012/03/09
151
0
多次字符串相加一定要用StringBuilder而不用 + 吗?

今天在写一个读取Java class File并进行分析的Demo时,偶然发现了下面这个场景(基于oracle jdk 1.8.0_144): 这是一个很简单的类,只完成了字符串的 + 操作,我们查看对应生成的class文件的o...

since1986
2017/11/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

零基础学画画应该从哪开始?

零基础学画画应该从哪开始?一种是从小有兴趣,喜欢涂鸦,喜欢将自己的创意和想法表现出来;另一种是长大后审美提高,开始对绘画艺术感兴趣,从而开始从零基础学起。 推荐大家可以搜一下:轻微...

设绘嗨
16分钟前
2
0
你编写的程序高效、优雅吗?阿里架构师教你编写高效优雅Java程序

面向对象 构造器参数太多怎么办? 用 builder 模式,用在 1、5 个或者 5 个以上的成员变量 2、参数不多,但是在未来,参数会增加 Builder 模式: 属于对象的创建模式,一般有 1. 抽象建造者:...

kx33389
21分钟前
1
0
PDF 文档操作Java类库Spire.PDF for Java v2.7.6发布上线!| 附下载

Spire.PDF for Java是一款专门对 PDF 文档进行操作的 Java 类库。该类库的主要功能在于帮助开发人员在 Java 应用程序(J2SE和J2EE)中生成 PDF 文档和操作现有 PDF 文档,并且运行环境无需安...

mnrssj
29分钟前
1
0
初探云原生应用管理(二): 为什么你必须尽快转向 Helm v3

在研究了一番“开放云原生应用中心(AppHub)”之后,程序员小张似乎已经明白了“云原生应用”到底是怎么一回事情。 “不就是 Helm 嘛!” 这不,小张这就准备把自己开发多年的“图书馆管理系...

zhaowei121
33分钟前
0
0
「工具」三分钟了解一款思维导图工具:XMind Zen

一款非常实用的商业思维导图软件,融合艺术与创造力。致力于高效的可视化思维,强调软件的跨平台使用,帮助用户提高生产效率。 相关信息 · 操作系统:macOS / Windows / Linux · 官方网站:...

极光推送
34分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部