java简单地实现Tiny语言的词法分析器

只是简单地编写,实现了一些简单的功能,没有考虑到代码优化等问题。


Tiny语言定义

 

一、 字符集定义

1. <字符集> → <字母>│<数字>│<单界符>

2. <字母> → A│B│…│Z│a│b│…│z

3. <数字> → 012│…│9

4. <单界符> → +-*/=<>│()│[]:. │; │, │' %

 

二、 单词集定义

5<单词集> → <保留字>│<双界符>│<标识符>│<常数>│<单界符>

6<保留字> → and│array│begin│bool│call│case│char│const│do│double│else│end│false│for│if│int│not│of│or│procedure│program│read│real│repeat│set│stop│then│to│true│until│var│while│write

7<双界符> → <=│>=│:= │/*│*/│

8<标识符> → <字母>│_ <字母>│_ <数字>│<标识符> <数字>│<标识符> <字母>│<标识符> _

9<常数> → <整数>│<布尔常数>│<字符常数>

10<整数> → <数字>│<整数> <数字>

11<布尔常数> → true│false

12<字符常数> → ' 除 ' 外的任意字符串'

 

三、 数据类型定义

13<类型> → int│bool│char

 

四、 表达式定义

14<表达式> → <算术表达式>│<布尔表达式>│<字符表达式>

15<算术表达式> → <算术表达式> + <项>│<算术表达式> - <项>│<项>

16<项> → <项> * <因子>│<项> / <因子>│<因子>

17<因子> → <算术量>│- <因子>

18<算术量> → <整数>│<标识符>│( <算术表达式> )

19<布尔表达式> → <布尔表达式> or <布尔项>│<布尔项>

20<布尔项> → <布尔项> and <布因子>│<布因子>

21<布因子> → <布尔量>│not <布因子>

22<布尔量> → <布尔常量>│<标识符>│( <布尔表达式> )│

<标识符> <关系符> <标识符>│<算术表达式> <关系符> <算术表达式>

23<关系符> → <│<=│>=│>│=

24.<字符表达式> → <字符常数>│<标识符>

 

五、 语句定义

25<语句> → <赋值句>│<if句>│<while句>│<repeat句>│<复合句>

26<赋值句> → <标识符> := <算术表达式>

27<if句>→ if <布尔表达式> then <语句>│if <布尔表达式> then <语句> else <语句>

28<while句> → while <布尔表达式> do <语句>

29<repeat句> → repeat <语句> until <布尔表达式>

30<复合句> → begin <语句表> end

31<语句表> → <语句> ;<语句表>│<语句>

 

 

六、 程序定义

32<程序> → program <标识符> ;<变量说明> <复合语句> .

33<变量说明> → var <变量定义>│ε

34<变量定义> → <标识符表> :<类型> ;<变量定义>│<标识符表> :<类型> ;

35<标识符表> → <标识符> ,<标识符表>│<标识符>

 

七、 Tiny语言单词编码

 

单  词

种别码

 

单  词

种别码

 

单  词

种别码

and

1

program

21

+

41

array

2

read

22

,

42

begin

3

real

23

-

43

bool

4

repeat

24

.

44

call

5

set

25

/

45

case

6

stop

26

/*

46

char

7

then

27

:

47

const

8

to

28

:=

48

do

9

true

29

;

49

double

10

until

30

<

50

else

11

var

31

<=

51

end

12

while

32

=

52

false

13

write

33

>

53

for

14

标识符

34

>=

54

if

15

整数

35

[

55

int

16

字符常数

36

]

56

not

17

(

37

_

57

of

18

)

38

{

58

or

19

*

39

}

59

procedure

20

*/

40

%

60


 能发现下列词法错误和指出错误性质和位置:

非法字符,即不是Tiny字符集的符号;例如¥等符号

字符常数缺右边的单引号(字符常数要求左、右边用单引号界定,不能跨行);

注释部分缺右边的界符*/(注释要求左右边分别用/**/界定,不能跨行);

发现错误后要能够继续编译下去,不能只报一个错误;


八、 测试程序与样板输出

 

测试程序1

program _example;

var  A,B,C,D:int;

begin

  A:=1; B:=5; C:=3; D:= '4';/* Variable initialization*/

  while A<C and B>D do

if A=1 then C:=C+1 else

  while A<=D do A:=A*2

end.

 

样板输出1:(要求在屏幕上显示)

(21 , program ) (34 , _example ) (49 , ; ) (31 , var ) (34 , A )

(42 , , ) (34 , B ) (42 , , ) (34 , C ) (42 , , )

(34 , D ) (47 , : ) (16 , int ) (49 , ; ) (3 , begin )

(34 , A) ( 48 , := ) (35 , 1 ) ( 49 , ; ) (34 , B )

(48 , := ) (35 , 5 ) (49 , ; ) (34 , C ) (48 , := )

(35 , 3 ) (49 , ; ) (34 , D ) (48 , := ) (36 , 4 )

(49, ; ) (32, while ) (34 , A ) (50 , < ) (34 , C )

(1, and ) (34 , B ) (53 , > ) (34 , D ) (9 , do )

(15, if ) (34 , A ) (52 , = ) (35 , 1 ) (27 , then )

(34, C ) (48 , := ) (34, C ) (41 , + ) (35 , 1 )

(11, else ) (32, while ) (34,A ) (51 , <= ) (34 , D )

(9, do ) (34,A ) (48 , := ) (34 , A ) (39 , * )

(35,2 ) (12 , end ) (44 , . )


代码如下:

package test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

/**
 * 
 * @author user
 *
 */
public class Test {
	
	//保存关键字的数组
	private static String []keyWord = {"and","array","begin","bool","call",
    "case","char","const","do","double","else","end","false","for","if",
    "int","not","of","or","procedure","program","read","real","repeat","set",
	"stop","then","to","true","until","var","while","write"};
	
	private static String dyhStr = "'";
	//保存符号的数组
	private static char []delimiter = {'(',')','*','+',',','-','.','/',':',';',
	'<','=','>','[',']','_','{','}','%',dyhStr.charAt(0)};

	private static FileInputStream fis;
	
	/**
	 * 判断是否是关键字
	 * @param str
	 * @return
	 */
	public static boolean isKeyWord(String str){
		boolean flag = false;
		for(int i = 0; i < keyWord.length; i++){
			if(keyWord[i].equals(str)){
				flag = true;
			}
		}
		return flag;
	}
	
	/**
	 * 判断是否是数字
	 * @param ch
	 * @return
	 */
	public static boolean isNumber(char ch){
		boolean flag = false;
		if(ch >= '0' && ch<= '9'){
			flag = true;
		}
		return flag;
	}
	
	/**
	 * 判断是否是字母
	 * @param ch
	 * @return
	 */
	public static boolean isLetter(char ch){
		boolean flag = false;
		if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')){
			flag = true;
		}
		return flag;
	}
	
	/**
	 * 判断是否是字符
	 * @param ch
	 * @return
	 */
	public static boolean isDlimeter(char ch){
		boolean flag = false;
		for(int i = 0; i < delimiter.length; i++){
			if(ch == delimiter[i]){
				flag = true;
			}
		}
		return flag;
	}
	
	
	/**
	 * 获取关键字的种别码
	 * @param str
	 * @return
	 */
	public static int getKeyWordIndex(String str){
		int keyWordIndex = 0;
		for(int i = 0; i< keyWord.length; i++){
			if(str.equals(keyWord[i]))
				keyWordIndex = i+1;  //数组下标从0开始
		}
		return keyWordIndex;
	}
	
	/**
	 * 获取单界符的种别码
	 * @param ch
	 * @return
	 */
	public static int getDelimiterIndex(char ch){
		int delimiterIndex = 0;
		switch (ch) {
		case '(':
			delimiterIndex = 37;
			break;
		case ')':
			delimiterIndex = 38;
			break;
		case '*':
			delimiterIndex = 39;
			break;
		case '+':
			delimiterIndex = 41;
			break;
		case ',':
			delimiterIndex = 42;
			break;
		case '-':
			delimiterIndex = 43;
			break;
		case '.':
			delimiterIndex = 44;
			break;
		case '/':
			delimiterIndex = 45;
			break;
		case ':':
			delimiterIndex = 47;
			break;
		case ';':
			delimiterIndex = 49;
			break;
		case '<':
			delimiterIndex = 50;
			break;
		case '=':
			delimiterIndex = 52;
			break;
		case '>':
			delimiterIndex = 53;
			break;
		case '[':
			delimiterIndex = 55;
			break;
		case ']':
			delimiterIndex = 56;
			break;
		case '_':
			delimiterIndex = 57;
			break;
		case '{':
			delimiterIndex = 58;
			break;
		case '}':
			delimiterIndex = 59;
			break;
		case '%':
			delimiterIndex = 60;
			break;
		}
		return delimiterIndex;
	}
	
	/**
	 * 获取双界符的种别码
	 * @param str
	 * @return
	 */
	public static int getDoubleDelimiter(String str){
		//":=",">=","<=","/*","*/"
		int index = 0;
		if(str.equals("*/")){
			index = 40;
		}
		if(str.equals("/*")){
			index = 46;
		}
		if(str.equals(":=")){
			index = 48;
		}
		if(str.equals("<=")){
			index = 51;
		}
		if(str.equals(">=")){
			index = 54;
		}
		return index;
	}
	
	/**
	 * 根据文本路径读取文本内容
	 * @param path
	 * @return
	 * @throws IOException 
	 */
	public static String readFile(String path) throws IOException{
		File file = new File(path);
		if(!file.exists() || file.isDirectory()){
			throw new FileNotFoundException();
		}
		fis = new FileInputStream(file);
		byte[] buffer = new byte[1024];
		StringBuffer stringBuffer = new StringBuffer();
		while((fis.read(buffer)) != -1){
			stringBuffer.append(new String(buffer));
			buffer = new byte[1024];
		}
		return stringBuffer.toString();
	}
	
	/**
	 * Tiny语言的词法分析
	 */
	public static void lexcialAnalysis(String filePath){	
		

		try{
			String fileTxt = readFile(filePath).trim();
			System.out.println("Tiny语言的源程序如下:");
			System.out.println(fileTxt);
			System.out.println("进行词法分析");
		}catch(IOException e){
			e.printStackTrace();
		}
		File file = new File(filePath);
		int row = 0, count = 0;//row行号,count统计二元组的个数
		char ch; 
		String lineStr; 
		BufferedReader bufferedReader;
		try{
			bufferedReader = new BufferedReader(new FileReader(file));
			//按行进行词法分析
			while((lineStr = bufferedReader.readLine()) != null){
				int i = 0;
				row++;
				int col = 1 ; //列号
				String dyh = "'";
				while(i <= lineStr.length()-1){
					ch = lineStr.charAt(i);
					//判断读取的第一个字符是否为字母或者是下划线
					if(isLetter(ch) || ch == '_'){
	/*********/			StringBuffer stringBuffer = new StringBuffer();
						stringBuffer.append(ch);
						col++;
						//读取下一个字符
						ch = lineStr.charAt(++i);
						//非第一个字符时,可以为字母,下划线和数字
						while((isLetter(ch)) || isNumber(ch) || ch == '_'){
							stringBuffer.append(ch);
							//如果读取到行的末尾则跳出循环,否则继续读取
							if(i == lineStr.length() - 1){
								i++;
								break;
							}
							else{
								ch = lineStr.charAt(++i);
							}
							col++;
						}
						
						//判断当前字符串是否是关键字
						if(isKeyWord(stringBuffer.toString())){
							//获取该关键字的种别码
							int kindCode = getKeyWordIndex(stringBuffer.toString());
							//输出该关键字的二元组
							System.out.print("("+ kindCode + "," + stringBuffer.toString() + ")"+ "  ");
							//二元组个数加1
							count++;
						}
						//标识符,输出标识符的二元组
						else{
							System.out.print("(" + 34 + ","+ stringBuffer.toString() +")"+ "  ");
							count++;
						}
						//每5个二元组换行
						if(count % 5 == 0){
							System.out.println();
						}
					}
					//如果是单界符
					else if(isDlimeter(ch)){
						StringBuffer stringBuffer = new StringBuffer();
						
						//如果是','或';'或'=','.',直接输出二元组
						if((ch == ',')||(ch == ';')||(ch == '=')||(ch == '.')){
							System.out.print("(" + getDelimiterIndex(ch) + "," + ch + ")" + "  ");
							i++;
							col++;
							count++;
						}
						//如果是'('或')'或'['或']',直接输出二元组
						else if((ch == '(')||(ch == ')')||(ch == '[')||(ch == ']')){
							System.out.print("(" + getDelimiterIndex(ch) + "," + ch + ")" + "  ");
							i++;
							col++;
							count++;
						}
						//如果是'+'或'-'或'*',直接输出二元组
						else if((ch == '+')||(ch == '-')||(ch == '*')){
							System.out.print("(" + getDelimiterIndex(ch) + "," + ch + ")" + "  ");
							i++;
							col++;
							count++;
						}
						//如果是'>'或'<'或':',需要继续读取一个字符进行判断是否是双界符
						else if((ch == '>')||(ch == '<')||(ch == ':')){
							stringBuffer.append(ch);
							col++;
							//读取下一个字符
							char nextCh = lineStr.charAt(++i); 
							//如果字符为'='
							if(nextCh == '='){
								stringBuffer.append(nextCh);
								col++;
								//输出双界符相关的二元数组
								System.out.print("(" + getDoubleDelimiter(stringBuffer.toString()) //
													+ "," + stringBuffer.toString() + ")" + "  ");
								i++;
								count++;
							}
							//直接输出单界符'>'或'<'或':'
							else{
								System.out.print("(" + getDelimiterIndex(ch) + "," + ch + ")" + "  ");
								count++;
							}
						}
						//如果读取的字符为/或'或"
						else if((ch == '/')||ch == dyh.charAt(0)){
							stringBuffer.append(ch);
							col++;
							if(i == lineStr.length() -1){
								i++;
								break;
							}
							//继续读取字符
							else{
								ch = lineStr.charAt(++i);
							}
							
							if(ch == '*'){
								stringBuffer.append(ch);
								ch = lineStr.charAt(++i);
								col++;
								while(ch != '*'){
									if(i == lineStr.length() - 1){
										i++;
										System.out.print("error:注释不匹配,第" + row +
												"行,第" + col + "列");
										break;
									}
									else{
										ch = lineStr.charAt(++i);
										col++;
									}
								}
								if(i <= lineStr.length()){
									break;
								}
								else{
									ch = lineStr.charAt(++i);
								}
								col++;
								if(ch == '/'){
									i++;
									continue;
								}
								else{
									System.out.print("error:注释不匹配"+"第"+row+"行,第"+col+"列");
								}
							}
							if(stringBuffer.charAt(0) == dyh.charAt(0)){
								StringBuffer stringBuffer1 = new StringBuffer();
								stringBuffer1.append(ch);
								col++;
								if(i == lineStr.length() - 1){
									i++;
									break;
								}
								else{
									ch = lineStr.charAt(++i);
									col++;
									while(ch != dyh.charAt(0)){
										stringBuffer.append(ch);
										if(i == lineStr.length() - 1){
											i++;
											break;
										}
										else{
											//继续读取字符
											ch = lineStr.charAt(++i);
											col++;
										}
									}
								}
								if( ch == dyh.charAt(0)){
									//输出的是字符常数
									System.out.print("(" + 36 + "," + stringBuffer1.toString() + ")" + "  ");
									count++;
								}
								else{
									System.out.print("error:单引号不匹配"+"第"+row+"行,第"+col+"列");
								}
								i++;
							}
						}
						if(count % 5 == 0){
							System.out.println();
						}
					}
					//非法字符判断
					else if(isDlimeter(ch) == false && isNumber(ch) == false && isLetter(ch) == false && ch != ' ') {
						System.out.print("error:出现非法字符:"+ch+",第"+row+"行,第"+col+"列");
						i++;
						col++;
					}
					//第一次读入的是数字
					else if(isNumber(ch)){
						StringBuffer stringBuffer = new StringBuffer();
						stringBuffer.append(ch);
						col++;
						ch = lineStr.charAt(++i);
						if(isNumber(ch)){
							while(isNumber(ch)){
								stringBuffer.append(ch);
								col++;
								ch = lineStr.charAt(++i);
							}
							System.out.print("(" + 35 + "," + stringBuffer.toString() + ")" + "");
							count++;
						}
						//一位数时,输出二元组 
						else {
							System.out.print("(" + 35 + "," + stringBuffer.toString()+ ")" + " ");
							count++;
							}
						if(isLetter(ch)){
							while(isLetter(ch)){
								stringBuffer.append(ch);
								col++;
								ch = lineStr.charAt(++i);
							}
							System.out.print("error:非法字符"+ stringBuffer.toString() + " 第 "+ row +" 行,第"+col+" 列出错");
						}
						if(count % 5 == 0){
							System.out.println();
						}
					}
					else{
						i++;
						col++;
					}
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public static void main(String []args){
		Scanner sc = new Scanner(System.in,"UTF-8");
		System.out.println("姓名:xxx   班级:xx软件工程xx班   学号:123456789");
		System.out.println("请输入文件路径,例如:D://test.txt");
		lexcialAnalysis(sc.nextLine());
	}
}


运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值