词法分析器 Tokenizer 自己就是一个状态机,生成这个状态机有不少种方法,而我打算采起手写的方式。由于 tao 语言的词法仍是相对比较简单的,手写不成问题。
先新建一个LexicalAnalysis.java 于 src/com/taozeyu/taolan/analysis之中。java
package com.taozeyu.taolan.analysis; public class LexicalAnalysis { private static enum State { Normal, Identifier, Sign, Annotation, String, RegEx, Space; } }
看看其中定义的 State 枚举类型,其中有6种类型与 Token 的类型对应。特别的,Normal 类型表示状态能够转化成任何一种单词类型的状态。我仍是贴一张图来描述着7种状态吧。程序员
如图所示,Normal 状态做为状态机的初始状态,也是各个其余状态的中转状态。状态机不断从源代码(即一个字符串)中读入一个一个字符,读到不一样的字符将使状态机的状态从一个状态变化到另一个状态。函数
例如,在 Normal 状态下读到了“#”将使状态变为 Annotation ,反过来若是继续读到一个“\n"即换行符号,则会从 Annotation 状态回到 Normal 状态。固然,对于 Identifier、 Sign、Space 的状态变化更为复杂一点,但仅凭当前读入的那一个字符就能够变化到正确的状态(图中没有表现)。spa
此外,当源代码读完了,若是状态机处于Normal状态,此时应该生成一个EndSymbol。但若是此时不处于 Normal 状态,那就有问题了,必须抛出一个异常。(这种状况是程序员把源代码自己写错了,例如最后一个字符串少右边的"之类的。)
至此,我就能够知道 LexicalAnalysis 类应该有那些函数可供(Parser)调用啦。code
package com.taozeyu.taolan.analysis; public class LexicalAnalysis { private static enum State { Normal, Identifier, Sign, Annotation, String, RegEx, Space; } public LexicalAnalysis(Reader reader) { //TODO } Token read() throws IOException, LexicalAnalysisException { //TODO } }
至此,语法分析器 Parser 能够不断调用 read() 函数来得到 Token 对象,直到读到 EndSymbol 或抛出异常为止。注意 read() 函数的声明中 throws LexicalAnalysisException 这段。当这个异常被抛出,说明源代码写错了。这不是编译器的错,而是程序员的错,编译器只管把这个错报出来,让程序员去改代码。orm
固然对于程序员而言,这是个语法错误。可是既然我是在写编译器,我可能要把这些错误分得更细一点。由于这个错误是在单词化(Tokenization)阶段抛出的,所以咱们将其称之为词法错误吧,以便区分。对象