http://www.cnblogs.com/xuqiang/archive/2010/09/21/1953501.html
Main.java
/* * 主程式 */ import java.io.*; import lexer.*; public class Main { public static void main(String[] args) throws IOException { Lexer lexer = new Lexer(); while (lexer.getReaderState() == false) { lexer.scan(); } /* 儲存相關資訊 */ lexer.saveTokens(); lexer.saveSymbolsTable(); } }
Lexer.java
package lexer; import java.io.*; import java.util.*; import symbols.*; public class Lexer { public static int line = 1; /* 記錄行號 */ char peek = ' '; /* 下一個讀入字元 */ Hashtable<String, Word> words = new Hashtable<String, Word>(); /* 符號表 */ private Hashtable<Token, String> table = new Hashtable<Token, String>(); /* token序列 */ private List<String> tokens = new LinkedList<String> (); /* 讀取檔案變數 */ BufferedReader reader = null; /* 儲存當前是否讀取到了檔案的結尾 */ private Boolean isEnd = false; /* 是否讀取到檔案的結尾 */ public Boolean getReaderState() { return this.isEnd; } /* 儲存儲存在table中的 */ public void saveSymbolsTable() throws IOException { FileWriter writer = new FileWriter("符號表.txt"); writer.write("[符號] [符號類型資訊]\n"); writer.write("\r\n"); Enumeration<Token> e = table.keys(); while( e.hasMoreElements() ){ Token token = (Token)e.nextElement(); String desc = table.get(token); /* 寫入檔案 */ writer.write(token + "\t\t\t" + desc + "\r\n"); } writer.flush(); } /* 儲存Tokens */ public void saveTokens() throws IOException { FileWriter writer = new FileWriter("Tokens表.txt"); writer.write("[符號] \n"); writer.write("\r\n"); for(int i = 0; i < tokens.size(); ++i) { String tok = (String)tokens.get(i); /* 寫入檔案 */ writer.write(tok + "\r\n"); } writer.flush(); } void reserve(Word w) { words.put(w.lexme, w); } /* * 建構函式中將關鍵字和類型添加到hashtable words中 */ public Lexer() { /* 初始化讀取檔案變數 */ try { reader = new BufferedReader(new FileReader("輸入.txt")); } catch(IOException e) { System.out.print(e); } /* 關鍵字 */ this.reserve(new Word("if", Tag.IF)); this.reserve(new Word("then", Tag.THEN)); this.reserve(new Word("else", Tag.ELSE)); this.reserve(new Word("while", Tag.WHILE)); this.reserve(new Word("do", Tag.DO)); /* 類型 */ this.reserve(Word.True); this.reserve(Word.False); this.reserve(Type.Int); this.reserve(Type.Char); this.reserve(Type.Bool); this.reserve(Type.Float); } public void readch() throws IOException { /* 這裡應該是使用的是 */ peek = (char)reader.read(); if((int)peek == 0xffff){ this.isEnd = true; } // peek = (char)System.in.read(); } public Boolean readch(char ch) throws IOException { readch(); if (this.peek != ch) { return false; } this.peek = ' '; return true; } public Token scan() throws IOException { /* 消除空白 */ for( ; ; readch() ) { if(peek == ' ' || peek == '\t') continue; else if (peek == '\n') line = line + 1; else break; } /* 下面開始分割關鍵字,標識符等資訊 */ switch (peek) { /* 對於 ==, >=, <=, !=的區分使用狀態機器實現 */ case '=' : if (readch('=')) { tokens.add("=="); return Word.eq; } else { tokens.add("="); return new Token('='); } case '>' : if (readch('=')) { tokens.add(">="); return Word.ge; } else { tokens.add(">"); return new Token('>'); } case '<' : if (readch('=')) { tokens.add("<="); return Word.le; } else { tokens.add("<"); return new Token('<'); } case '!' : if (readch('=')) { tokens.add("!="); return Word.ne; } else { tokens.add("!"); return new Token('!'); } } /* 下面是對數位識別,根據文法的規定的話,這裡的 * 數字只要是能夠識別整數就行. */ if(Character.isDigit(peek)) { int value = 0; do { value = 10 * value + Character.digit(peek, 10); readch(); } while (Character.isDigit(peek)); Num n = new Num(value); tokens.add(n.toString()); //table.put(n, "Num"); return n; } /* * 關鍵字或者是標識符的識別 */ if(Character.isLetter(peek)) { StringBuffer sb = new StringBuffer(); /* 首先得到整個的一個分割 */ do { sb.append(peek); readch(); } while (Character.isLetterOrDigit(peek)); /* 判斷是關鍵字還是標識符 */ String s = sb.toString(); Word w = (Word)words.get(s); /* 如果是關鍵字或者是類型的話,w不應該是空的 */ if(w != null) { // table.put(w, "KeyWord or Type"); tokens.add(w.toString()); return w; /* 說明是關鍵字 或者是類型名 */ } /* 否則就是一個標識符id */ w = new Word(s, Tag.ID); tokens.add(w.toString()); table.put(w, "id"); words.put(s, w); return w; } /* peek中的任一字元都被認為是詞法單元返回 */ Token tok = new Token(peek); // table.put(tok, "Token or Seprator"); if ((int)peek != 0xffff ) tokens.add(tok.toString()); peek = ' '; return tok; } }
Num.java
package lexer; public class Num extends Token{ public final int value; public Num(int v) { super(Tag.NUM); this.value = v; } public String toString() { return "" + value; } }
Tag.java
package lexer; public class Tag { public final static int AND = 256, BASIC = 257, BREAK = 258, DO = 259, ELSE = 260, EQ = 261, /* == */ FALSE = 262, GE = 263, ID = 264, IF = 265, INDEX = 266, LE = 267, MINUS = 268, NE = 269, NUM = 270, OR = 271, REAL = 272, TEMP = 273, TRUE = 274, WHILE = 275, /* 後面添加 */ THEN = 276; }
Token.java
package lexer; public class Token { public final int tag; public Token(int t) { this.tag = t; } public String toString() { return "" + (char)tag; } public static void main(String[] args) { Token tok = new Token('a'); System.out.println(tok); } }
Word.java
/* * 類word用於管理保留字,標識符以及像&&這樣的複合單詞元素 。 */ package lexer; public class Word extends Token { public String lexme = ""; public Word (String s, int t) { super(t); this.lexme = s; } public String toString() { return this.lexme; } public static final Word and = new Word("&&", Tag.AND), or = new Word("||", Tag.OR), eq = new Word ("==", Tag.EQ), ne = new Word("!=", Tag.NE), le = new Word("<=", Tag.LE), ge = new Word(">=", Tag.GE), minus = new Word("minus", Tag.MINUS), True = new Word("true", Tag.TRUE), False = new Word("false", Tag.FALSE), temp = new Word("t", Tag.TEMP); }
Type.java
/* * 說明資料類型 */ package symbols; import lexer.*; public class Type extends Word{ public Type(String s, int tag) { super(s, tag); } public static final Type Int = new Type("int", Tag.BASIC), Float = new Type("float", Tag.BASIC), Char = new Type ("char", Tag.BASIC), Bool = new Type("bool", Tag.BASIC); }
============
http://freewxy.iteye.com/blog/870016
什麼是詞法。
所謂詞法,原始碼由字元流組成,字元流中包括關鍵字,變數名,方法名,括弧等等符號,其中變數名要滿足不能包括標點符號,不能以數字開頭的數字與字母的字串這個條件,對於括弧要成對出現等等,這就是詞法;
什麼是詞法分析。
詞法分析階段是編譯過程的第一個階段。這個階段的任務是從左至右一個字元一個字元地讀入來源程式,即對構成來源程式的字元流進行掃描然後根據構詞規則識別單詞(也稱單詞符號或符號)。
待分析的簡單語言的詞法:
1) 關鍵字
begin if then while do end
2) 運算子和界符
:= + - * / < <= > >= <> = ; ( ) #
3) 其他單詞是標識符(ID)和整形常數(NUM),通過以下正規式定義:
ID=letter(letter|digit)*
NUM=digitdigit*
4) 空格由空白、定位字元和分行符號組成。空格一般用來分隔ID、NUM、運算子、界符和關鍵字,詞法分析階段通常被忽略。
各種單詞符號對應的種別編碼
| 單詞符號 |
種別碼 |
單詞符號 |
種別碼 |
| begin |
1 |
: |
17 |
| if |
2 |
:= |
18 |
| then |
3 |
< |
20 |
| while |
4 |
<> |
21 |
| do |
5 |
<= |
22 |
| end |
6 |
> |
23 |
| letter(letter|digit)* |
10 |
>= |
24 |
| digitdigit* |
11 |
= |
25 |
| + |
13 |
; |
26 |
| - |
14 |
( |
27 |
| * |
15 |
) |
28 |
| / |
16 |
# |
0 |
詞法剖析器的功能:
輸入:所給文法的來源程式字串
輸出:二元組(syn, token或sum)構成的序列。
syn為單詞種別碼;
token為存放的單詞自身字串;
sum為整形常數。
例如:對來源程式begin x:=9;if x>0 then x:=2*x+1/3;end# 經詞法分析後輸出如下序列:(1,begin)(10,’x’) (18,:=) (11,9) (26,;) (2,if)……
流程圖: