一、实验目的
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类,并依次输出各个单词的内部编码及单词符号自身值(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。
二、实验预习提示
1、词法分析器的功能和输出格式
词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。本实验中,采用的是一类符号一种别码的方式。
2、“超前搜索”方法
三、实验过程和指导
(一)准备:
1、阅读课本有关章节,明确语言的语法,写出基本保留字、标识符、常数、运算符、分隔符和程序例子。
2、初步编制好程序。
3、准备好多组测试数据。
(二)上课上机:
将源代码拷贝到机上调试,发现错误,再修改完善。
第二次上机调试通过。
(三)程序要求:
程序输入/输出示例:
如源程序为C语言。输入如下一段:
main()
{
int a,b;
a = 10;
b = a + 20;
}
要求输出如下图:
(2,”main”)
(5,”(“)
(5,”)“)
(5,”{“)
(1,”int”)
(2,”a”)
(5,”,”)
(2,”b”)
(5,”;”)
(2,”a”)
(4,”=”)
(3,”10”)
(5,”;”)
(2,”b”)
(4,”=”)
(2,”a”)
(4,”+”)
(3,”20”)
(5,”;”)
(5,”}“)
要求:
识别保留字:if、int、for、while、do、return、break、continue;单词种别码为1。
常数为无符号整形数;单词种别码为3。
运算符包括:+、-、*、/、=、、<、=、<=、!= ;单词种别码为4。
分隔符包括:,、;、{、}、(、); 单词种别码为5。
其他的都识别为标识符;单词种别码为2。
(四)程序思路(仅供参考):
这里以开始定义的C语言子集的源程序作为词法分析程序的输入数据。在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
1、定义部分:定义常量、变量、数据结构。
2、初始化:从文件将源程序全部输入到字符缓冲区中。
3、取单词前:去掉多余空白。
4、取单词后:去掉多余空白(可选,看着办)。
5、取单词:读出单词的每一个字符,组成单词,分析类型。(关键是如何判断取单词结束?取到的单词是什么类型的单词?)
6、显示结果。
(五)为了能设计好程序,注意以下事情:
1、模块设计:将程序分成合理的多个模块(函数),每个模块做具体的同一事情。
2、写出(画出)设计方案:模块关系简图、流程图、全局变量、函数接口等。
3、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
源代码
public class Work {
static StringBuffer token=new StringBuffer("");
static int index=0;//用于记录当前下标;
static int row=0,sum; //row 用于记录当前行数 ,sum 用于存储数字;
static String storage=""; //用于存放输入后的总字符串
//定义24个保留字
static String[] rwtab=new String[]{"if","while","do","void",
"int","for","break","return","continue"
};
public static void main(String[] args) {
System.out.println("请输入C语言源程序字符串(以#结尾):");
enter();
// System.out.println(storage);
do{
int case1 =analyzer();
switch(case1){
case 0:
break;
case 1:
System.out.println("("+case1+","+"“"+token+"”"+")");
break;
case 2:
System.out.println("("+case1+","+"“"+token+"”"+")");
break;
case 3:
System.out.println("("+case1+","+"“"+sum+"“"+")");
break;
case 4:
System.out.println("("+case1+","+"“"+token+"”"+")");
break;
case 5:
System.out.println("("+case1+","+"“"+token+"”"+")");
break;
case 6:
System.out.println("Error in row"+row+"!");
break;
}
}while(index!=storage.length());
}
/**
* 词法分析函数
* @return
*/
public static int analyzer() {
token.delete(0, token.length()); //置空token对象,清除
char ch=storage.charAt(index++);
while(ch==' '){
ch=storage.charAt(index++); //去除空格符号
}
//如果遇到回车符行加一
if(ch=='\n') {
row++;
}
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){ //可能是关键字或者自定义的标识符
while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){
token.append(ch);
ch=storage.charAt(index++);
}
index--;
// syn=1; //默认为识别出的字符串为自定义的标识符,种别码为1
String s=token.toString();
for(int i=0; i<rwtab.length; i++){
if(s.equals(rwtab[i])){
return 1;
}
}
return 2;
}
else if((ch>='0'&&ch<='9')){
sum=0;
while((ch>='0'&&ch<='9')){
sum=sum*10+ch-'0';
ch=storage.charAt(index++);
}
index--;
return 3;
}
else switch(ch){
case '<':
token.append(ch);
ch=storage.charAt(index++);
if(ch=='='){
token.append(ch);
}
else if(ch=='>'){
token.append(ch);
}
else{
index--;
}
return 4;
case '>':
token.append(ch);
ch=storage.charAt(index++);
if(ch=='='){
token.append(ch);
}
else{
index--;
}
return 4;
case '*':
token.append(ch);
ch=storage.charAt(index++);
if(ch=='*'){
token.append(ch);
}
else{
index--;
}
return 4;
case '=':
token.append(ch);
ch=storage.charAt(index++);
if(ch=='='){
token.append(ch);
}
else{
index--;
}
return 4;
case '/':
token.append(ch);
ch=storage.charAt(index++);
if(ch=='/'){
while(ch!=' '){
ch=storage.charAt(index++); //忽略掉注释,以空格为界定
}
return 0;
}
else{
index--;
}
return 4;
case '+':
token.append(ch);
return 4;
case '-':
token.append(ch);
return 4;
case ';':
token.append(ch);
return 5;
case '(':
token.append(ch);
return 5;
case ')':
token.append(ch);
return 5;
case '#':
token.append(ch);
return 0;
case '{':
token.append(ch);
return 5;
case '}':
token.append(ch);
return 5;
case ',':
token.append(ch);
return 5;
case '\n':
return 0;
default:
return 6;
}
}
/**
* 输入函数
*/
public static void enter() {
char ch;
String tempString=null;
Scanner sr=new Scanner(System.in);
do {
storage+="\n";
tempString=sr.nextLine();
storage+=tempString;
ch=tempString.charAt(tempString.length()-1);
}while(ch!='#');
sr.close();
}
}
效果图