如今,让咱们来动手写编译器的第一个个java文件吧。本章要写的类,是Token类。如其名字所示,这个类实例化的对象用于表示词法分析器 Tokenizer 的产物。同时,也做为下一阶段的语法分析器 Parser 的原料。java
让咱们开始吧!先新建一个Token.java 于 src/com/taozeyu/taolan/analysis之中。函数
package com.taozeyu.taolan.analysis; public class Token { public static enum Type { Keyword, Number, Identifier, Sign, Annotation, String, RegEx, Space, NewLine, EndSymbol; } final Type type; final String value; Token(Type type, String value) { //TODO } }
如以前章节讨论的同样,Token对象应该包含类型和语素两个属性。注意这个 Type 枚举类型,其内容就是我在上一章所说的 tao 语言应该具有的10种单词类型。this
我但愿词法分析器从源代码中提取出语素,并根据上下文推测出单词类型,从而构造出Token对象。但实际上,请注意Type这个枚举类的三个类型:编码
Keyword, Number, Identifier
这三个类型不一样之处?实际上这三个类型的形式极其相似(甚至 Keyword 和 Identifier 的形式是彻底相同的),而且能够仅经过语素准确断定其类型。所以,我但愿对词法分析器 Tokenizer 隐藏着三种类型的区别,将这三种类型统称 Identifier,以简化编码。code
Token(Type type, String value) { if(type == Type.Identifier) { char firstChar = value.charAt(0); if(firstChar >= '0' & firstChar < '9') { type = Type.Number; } else if(keywordsSet.contains(value)){ type = Type.Keyword; } } this.type = type; this.value = value; }
因而,Token 对 Tokenizer 隐藏了 Number、Keyword 类型。Tokenizer 只须要构造出 Identifier 类型便可,进一步细分将在 Token 的构造函数中进行。对象
特别的,构造函数中引用了一个 keywordsSet 变量。实际上这个变量应该包含全部 tao 语言的关键字。此处稍稍定义一下。字符串
private static final HashSet<String> keywordsSet = new HashSet<>(); static { keywordsSet.add("if"); keywordsSet.add("when"); keywordsSet.add("elsif"); keywordsSet.add("else"); keywordsSet.add("while"); keywordsSet.add("begin"); keywordsSet.add("until"); keywordsSet.add("for"); keywordsSet.add("do"); keywordsSet.add("try"); keywordsSet.add("catch"); keywordsSet.add("finally"); keywordsSet.add("end"); keywordsSet.add("def"); keywordsSet.add("var"); keywordsSet.add("this"); keywordsSet.add("null"); keywordsSet.add("throw"); keywordsSet.add("break"); keywordsSet.add("continue"); keywordsSet.add("return"); keywordsSet.add("operator"); }
好吧,tao 语言我能想出的可能有的关键字都在这里了。若是有遗漏或者多余,其实之后再回过头来改也没问题。编译器
特别的,对于 Annotation、String、RegEx ,它们在源代码中存在的形式和具体的语素并不彻底等同。io
^\s+\d+$
另外,EndSymbol 的语素必须为空,无论 Tokenizer 传入什么参数都必须如此。编译