java实现简单的词法分析仿真
?
什么是词法??
?
??所谓词法,源代码由字符流组成,字符流中包括关键字,变量名,方法名,括号等等符号,其中变量名要满足不能包括标点符号,不能以数字开头的数字与字母的字符串这个条件,对于括号要成对出现等等,这就是词法;
?
什么是词法分析?
?
??词法分析阶段是编译过程的第一个阶段。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。
?
待分析的简单语言的词法:
?
?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();} }}
?
?
文件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-->