什么是词法? 

 

  所谓词法,源代码由字符流组成,字符流中包括关键字,变量名,方法名,括号等等符号,其中变量名要满足不能包括标点符号,不能以数字开头的数字与字母的字符串这个条件,对于括号要成对出现等等,这就是词法;

 

什么是词法分析?

 

  词法分析阶段是编译过程的第一个阶段。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。

 

待分析的简单语言的词法:

 

 1) 关键字

  begin if then while do end

 2) 运算符和界符

  := + - * / < <= > >= <> = ; ( ) #

(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-->