http://www.cnblogs.com/xuqiang/archive/2010/09/21/1953501.html
Main.java
Lexer.java
Num.java
Tag.java
Token.java
Word.java
Type.java
============
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)……
流程图:
源码:
- public class 词法分析 {
- /* 初始化数据
- syn为单词种别码;
- token为存放的单词自身字符串;
- sum为整型常数。
- */
- static String prog;
- static char ch;
- static char[]token=new char[8];
- static int syn,p,m,n,sum;
- static //关键字表的初值
- String[] rwtable={"begin","if","then","while","do","end"};
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws IOException {
- //1、输入字符串
- //prog="begin x:=9; if x>0 then x:=2*x+1/3;end #";
- //1、从文件中读取字符串
- prog=dofile.readFileByChars("src/data.txt");
- //2、扫描输出
- p=0;
- do{
- scaner();
- switch(syn){
- case 11:System.out.print("("+syn+" , ");//单词符号:Digit digit*
- System.out.print(sum);
- System.out.println(")");
- break;
- case -1:System.out.println("error!");
- break;
- default:
- System.out.print("(");
- System.out.print(syn);
- System.out.print(" , ");
- String str=new String(token);
- System.out.print(str);
- System.out.println(")");
- }
- }while(syn!=0);
- }
- //扫描程序
- private static void scaner() throws IOException {
- // 1、初始化
- for(int i=0;i<8;i++)
- token[i]=' ';
- // 2、读字母
- ch=prog.charAt(p++);
- while(ch==' '){//如果是空格,则取下一个字符
- ch=prog.charAt(p++);
- }
- // 3、开始执行扫描
- // 1、是字母
- // 读标识符,查保留字表
- // 查到,换成属性字表,写到输出流
- // 没查到, 查名表,换成属性字,写到输出流
- if(ch>='a'&&ch<='z'){
- m=0;
- //获取完整单词
- while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){
- token[m++]=ch;
- ch=prog.charAt(p++);
- }
- token[m++]='\0';
- --p;
- syn=10;//单词符号为letter(letter|digit)*
- //判断是哪个关键字
- String newStr=new String(token);
- newStr=newStr.trim();
- //System.out.println("newStr:"+newStr);
- for(n=0;n<6;n++){
- //System.out.println("rwtable:"+rwtable[n]);
- if(newStr.equals(rwtable[n])){
- syn=n+1;
- System.out.println("syn 的值是:"+syn);
- break;
- }
- }
- token[m++]='\0';
- }
- // 2、是数字
- // 取数字,查常量表,换成属性字表,写到输出流
- else if(ch>='0'&&ch<='9'){
- while(ch>='0'&&ch<='9'){
- sum=sum*10+ch-'0';
- ch=prog.charAt(p++);
- }
- --p;
- syn=11;//digitdigit*
- token[m++]='\0';
- }
- // 3、是特殊符号
- // 查特殊符号表,换成属性字。写到输出流
- // 4、错误error
- // 4、是否分析结束
- // 未结束,到2
- // 结束,到出口
- else
- switch(ch){
- case'<':
- m=0;
- token[m++]=ch;
- ch=prog.charAt(p++);
- if(ch=='>'){
- syn=21;//<>
- }
- else if(ch=='='){
- syn=22;//<=
- token[m++]=ch;
- }
- else{
- syn=20;//<
- --p;
- }
- break;
- case'>':
- token[m++]=ch;
- ch=prog.charAt(p++);
- if(ch=='='){
- syn=24;//>=
- }
- else{
- syn=23;//>
- --p;
- }
- break;
- case':':
- token[m++]=ch;
- ch=prog.charAt(p++);
- if(ch=='='){
- syn=18;//:=
- token[m++]=ch;
- }
- else{
- syn=17;//:
- --p;
- }
- break;
- case'+':
- syn=13;token[0]=ch;token[1]='\0';break;
- case'-':
- syn=14;token[0]=ch;token[1]='\0';break;
- case'*':
- syn=15;token[0]=ch;token[1]='\0';break;
- case'/':
- syn=16;token[0]=ch;token[1]='\0';break;
- case'=':
- syn=25;token[0]=ch;token[1]='\0';break;
- case';':
- syn=26;token[0]=ch;token[1]='\0';break;
- case'(':
- syn=27;token[0]=ch;token[1]='\0';break;
- case')':
- syn=28;token[0]=ch;token[1]='\0';break;
- case'#':
- syn=0;token[0]=ch;token[1]='\0';break;
- default:
- syn=-1;
- }
- File txt=new File("src/nihao.txt");
- if(!txt.exists()){
- txt.createNewFile();
- }
- byte[] bytes=new byte[token.length];//定义一个长度与需要转换的char数组相同的byte数组
- for(int i=0;i<bytes.length ;i++){//循环将char的每个元素转换并存放在上面定义的byte数组中
- byte b=(byte)token[i];//将每个char转换成byte
- bytes[i]=b;//保存到数组中
- }
- FileOutputStream fos;
- try {
- fos = new FileOutputStream(txt,true);
- fos.write(syn);
- fos.write(bytes);
- fos.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
public class 词法分析 {
/* 初始化数据
syn为单词种别码;
token为存放的单词自身字符串;
sum为整型常数。
*/
static String prog;
static char ch;
static char[]token=new char[8];
static int syn,p,m,n,sum;
static //关键字表的初值
String[] rwtable={"begin","if","then","while","do","end"};
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1、输入字符串
//prog="begin x:=9; if x>0 then x:=2*x+1/3;end #";
//1、从文件中读取字符串
prog=dofile.readFileByChars("src/data.txt");
//2、扫描输出
p=0;
do{
scaner();
switch(syn){
case 11:System.out.print("("+syn+" , ");//单词符号:Digit digit*
System.out.print(sum);
System.out.println(")");
break;
case -1:System.out.println("error!");
break;
default:
System.out.print("(");
System.out.print(syn);
System.out.print(" , ");
String str=new String(token);
System.out.print(str);
System.out.println(")");
}
}while(syn!=0);
}
//扫描程序
private static void scaner() throws IOException {
// 1、初始化
for(int i=0;i<8;i++)
token[i]=' ';
// 2、读字母
ch=prog.charAt(p++);
while(ch==' '){//如果是空格,则取下一个字符
ch=prog.charAt(p++);
}
// 3、开始执行扫描
// 1、是字母
// 读标识符,查保留字表
// 查到,换成属性字表,写到输出流
// 没查到, 查名表,换成属性字,写到输出流
if(ch>='a'&&ch<='z'){
m=0;
//获取完整单词
while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){
token[m++]=ch;
ch=prog.charAt(p++);
}
token[m++]='\0';
--p;
syn=10;//单词符号为letter(letter|digit)*
//判断是哪个关键字
String newStr=new String(token);
newStr=newStr.trim();
//System.out.println("newStr:"+newStr);
for(n=0;n<6;n++){
//System.out.println("rwtable:"+rwtable[n]);
if(newStr.equals(rwtable[n])){
syn=n+1;
System.out.println("syn 的值是:"+syn);
break;
}
}
token[m++]='\0';
}
// 2、是数字
// 取数字,查常量表,换成属性字表,写到输出流
else if(ch>='0'&&ch<='9'){
while(ch>='0'&&ch<='9'){
sum=sum*10+ch-'0';
ch=prog.charAt(p++);
}
--p;
syn=11;//digitdigit*
token[m++]='\0';
}
// 3、是特殊符号
// 查特殊符号表,换成属性字。写到输出流
// 4、错误error
// 4、是否分析结束
// 未结束,到2
// 结束,到出口
else
switch(ch){
case'<':
m=0;
token[m++]=ch;
ch=prog.charAt(p++);
if(ch=='>'){
syn=21;//<>
}
else if(ch=='='){
syn=22;//<=
token[m++]=ch;
}
else{
syn=20;//<
--p;
}
break;
case'>':
token[m++]=ch;
ch=prog.charAt(p++);
if(ch=='='){
syn=24;//>=
}
else{
syn=23;//>
--p;
}
break;
case':':
token[m++]=ch;
ch=prog.charAt(p++);
if(ch=='='){
syn=18;//:=
token[m++]=ch;
}
else{
syn=17;//:
--p;
}
break;
case'+':
syn=13;token[0]=ch;token[1]='\0';break;
case'-':
syn=14;token[0]=ch;token[1]='\0';break;
case'*':
syn=15;token[0]=ch;token[1]='\0';break;
case'/':
syn=16;token[0]=ch;token[1]='\0';break;
case'=':
syn=25;token[0]=ch;token[1]='\0';break;
case';':
syn=26;token[0]=ch;token[1]='\0';break;
case'(':
syn=27;token[0]=ch;token[1]='\0';break;
case')':
syn=28;token[0]=ch;token[1]='\0';break;
case'#':
syn=0;token[0]=ch;token[1]='\0';break;
default:
syn=-1;
}
File txt=new File("src/nihao.txt");
if(!txt.exists()){
txt.createNewFile();
}
byte[] bytes=new byte[token.length];//定义一个长度与需要转换的char数组相同的byte数组
for(int i=0;i<bytes.length ;i++){//循环将char的每个元素转换并存放在上面定义的byte数组中
byte b=(byte)token[i];//将每个char转换成byte
bytes[i]=b;//保存到数组中
}
FileOutputStream fos;
try {
fos = new FileOutputStream(txt,true);
fos.write(syn);
fos.write(bytes);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
文件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-->