如今,讓咱們來動手寫編譯器的第一個個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 傳入什麼參數都必須如此。編譯