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)……
流程图:
源码:
Java代码
文件data.txt中的内容为:
begin x:=9; if x>0 then x:=2*x+1/3;end #
程序执行结果(控制台输出):
打开文件 src/data.txt 读取内容为:
beginx:=9;ifx>0thenx:=2*x+1/3;end#
syn 的值是:1
(1 , begin)(10,x)
(18,:=)
(11,9)
(26,;)
syn的值是:2
(2,if)
(10,x)
(23,>)
(11,90)
syn的值是:3
(3,then)
(10,x)
(13,+)
(11,902)
(15,*)
(10,x)
(13,+)
(11,9021)
(16,)
(11,90213)
(26,;)
syn的值是:6
(6,end)
(0,#)
<!--EndFragment-->