一、 实验目的
设计并实现一个包含预处理功能的词法分析程序,加深对编译中词法分析过程的理解。
二、 实验要求
1、实现预处理功能
源程序中可能包含有对程序执行无意义的符号,要求将其剔除。
首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;把多个空白符合并为一个;去掉注释。
2、实现词法分析功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。其中,
syn为单词种别码。
Token为存放的单词自身字符串。
Sum为整型常量。
具体实现时,可以将单词的二元组用结构进行处理。
3、待分析的C语言子集的词法
1)关键字
main if then while do static int double struct break else long switch case typedef char return const float short continue for void default sizeof do
所有的关键字都是小写。
2)运算符和界符
** + - * / : := < <> <= > >= = ; ( ) # **
3)其他标记ID和NUM
通过以下正规式定义其他标记:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…
4)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。
4、各种单词符号对应的种别码
表1 各种单词符号的种别码
5、 词法分析程序的主要算法思想
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到的单词符号的第一个字符的种类,拼出相应的单词符号。
其中初值包括如下两方面:
(1) 关键字表初值
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下:
char *rwtab[27]={“main”,”if”,”then”,”while”,”do”,” static”,”int”,” double”,”struct”,”break”,”else”,”long”,”switch”,”case”,”typedef”,”char”,”return”,”const”,”float”,”short”,”continue”,”for”,”void”,”default”,”sizeof”,”do”};
(2) 程序中需要用到的主要变量:syn,token和sum。
2. 扫描子程序的算法思想
首先设置三个变量:token用来存放构成单词符号的字符串;sum用来存放整型单词;syn用来存放单词符号的种别编码。
Java源代码:
import java.io.*;
import java.io.FileReader;
import java.io.FileWriter;
public class test {
public static void main(String ags[])
{
clearSpace cs=new clearSpace("d://文档/实验/test.txt");//处理文本目录,需要自行设置
cs.readChar(); //从文件读取字符
cs.clear(); //清空多余空白
cs.writeChar("d://文档/实验/cleared.txt"); //将结果写入文件
analyzeWord aw=new analyzeWord("d://文档/实验/cleared.txt",cs.t);
aw.readChar();
aw.analyze(); //进行分析并打印结果
}
}
class clearSpace
{
FileReader fr=null;
FileWriter fw=null;
String fileAddress;
char r[]=new char[1000];//保存读取字符
char w[]=new char[1000];//保存有效字符
int t;
clearSpace(String fileAddress)
{
this.fileAddress=fileAddress;
}
public void readChar()
{
try {
fr=new FileReader(fileAddress);
int n;
while ((n=fr.read(r))!=-1)
{
//将文本数据读入字符数组
t=n;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void clear()
{
int i,j=0;
for(i=0;i<t;i++)
{
if(r[i]==' ')//去掉多余空格
{
if (w[j-1]!=' ') {
w[j++]=' ';
}
while(r[++i]==' ')
{
}
i--;
}
else if(r[i]=='\t') //去掉制表符
{
if (w[j-1]!=' ') {
w[j++]=' ';
}
while(r[++i]=='\t')
{
}
i--;
}
else if(r[i]=='\n') //去掉换行
{
if (w[j-1]!=' ') {
w[j++]=' ';
}
while(r[++i]=='\n')
{
}
i--;
}
else if(r[i]=='/' && r[i+1]=='/') //去掉注释
{
while (r[++i]!='\n')
{
}
i--;
}
else if(r[i]=='\r') //去掉回车
{
if (w[j-1]!=' ') {
w[j++]=' ';
}
// while (r[++i]!='\n')
// {
// }
// i--;
}
else{
w[j++]=r[i]; //其他字符
}
}
}
public void writeChar(String Address)
{
try {
fw=new FileWriter(Address);
fw.write(w);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class analyzeWord
{
String rwtab[]={" ","main","if","then","while","do","static","int","double","struct",
"break","else","long","switch","case","typedef","char","return","const",
"float","short","continue","for","void","sizeof"};
String fileAddress;
char rd[]=new char[1000];
FileReader fr=null;
int n,m=0,t;
analyzeWord(String fileAddress,int t)
{
this.fileAddress=fileAddress;
this.t=t;
}
public void readChar()
{
try {
fr=new FileReader(fileAddress);
while ((n=fr.read(rd))!=-1)
{
//从文本中读取数据到字符数组
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void analyze()
{
int i,j=0,syn=0;
int c=0;
char token[];
char r[];
String rds=new String(rd).trim();
r=rds.toCharArray();
for(i=0;i<r.length;i++)
{
token = new char[100];
if((r[i]>='A'&& r[i]<='Z') || (r[i]<='z' && r[i]>='a'))
{
while ((r[i]>='A'&& r[i]<='Z') || (r[i]<='z' && r[i]>='a') ||(r[i]>='0'&&r[i]<='9') )
{
token[j++]=r[i];
i++;
}
i--;
syn=25; //先将syn赋值
String temp=new String(token).trim();
for(j=1;j<=24;j++)
{
if(temp.equals(rwtab[j]))
{
syn=j; //如果存在关键字则重新赋值
break;
}
}
}//识别字母开头的字母数字串
else if(r[i]>='0'&&r[i]<='9')
{
while ((r[i]>='0'&&r[i]<='9') )
{
token[j++]=r[i];
i++;
}
syn=26;
i--;
}//识别数字NUM
else if(r[i]==' ')
{
continue; //识别空格并直接进入下一次循环
}
else if(r[i]=='*'&&r[i+1]=='*') //识别**
{
token[j++]='*';
token[j]='*';
syn=31;
i++;
}
else if(r[i]=='='&&r[i+1]=='=') //识别==
{
token[j++]='=';
token[j]='=';
syn=32;
i++;
}
else if(r[i]=='<'&&r[i+1]=='>') //识别<>
{
token[j++]='<';
token[j]='>';
syn=34;
i++;
}
else if(r[i]=='<'&&r[i+1]=='=') //识别<=
{
token[j++]='<';
token[j]='=';
i++;syn=35;
}
else if(r[i]=='>'&&r[i+1]=='>') //识别>=
{
token[j++]='>';
token[j]='=';
syn=37;
i++;
}
else { //其他符号
token[j]=r[i];
switch (token[j])
{
case '+':
syn=27;
break;
case '-':
syn=28;
break;
case '*':
syn=29;
break;
case '/':
syn=30;
break;
case '<':
syn=33;
break;
case '>':
syn=36;
break;
case '=':
syn=38;
break;
case '[':
syn=39;
break;
case ']':
syn=40;
break;
case ';':
syn=41;
break;
case '(':
syn=42;
break;
case ')':
syn=43;
break;
case '#':
syn=0;
break;
default:
syn=-1;
break;
}
}
j=0;
c++;
if (syn==-1)
{
System.out.print("(");
System.out.print(new String(token));
System.out.println(" ,无法识别该字符!)");
}
else {
System.out.print("(");
System.out.print(new String(token));
System.out.println(","+syn+")");
}
}
System.out.println("词法分析完毕!");
}
}