一、 实验目的
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
这里以开始定义的c语言子集的源程序作为词法分析程序的输入数据。在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
二、 实验要求
程序能够从左到右一个字符一个字符地读入源程序,并对构成的源程序的字符流进行扫描和分解,从而识别出一个个单词(也称单词符号或符号)。并给出单词的值和属性。
三、 实验步骤
(一)提示词法分析程序的运行流程
1、主函数main():
2、打开要分析的C源程序,若不能正确打开,则报错。
3、 先从源程序中读入一个字符ch,然后进行如下处理:
1)ch是字符:转入关键字和标识符处理子函数;
2)ch是数字:转入数字处理函数;
3)ch是其他字符:转入其他字符处理子函数;
4)结束。
(二)相关规定
1、假设其中关键字包括:“if”,“else”,“for”,“while”,“do”,“return”,“break”,“continue”
2、界符包括:",", “;”, “{”, “}”, “(”, “)”
3、算术运算包括:"+","-","*","/"
4、关系运算法包括"<","<=","=",">",">=","<>"
5、常量和标识符的数位最大为20;
(三)提示
关键字和标识符处理过程用函数来实现,假设为alphaprocess(char buffer)
1、将buffer送入临时数组中(设为alphatp),再读入一个字符至buffer;
2、判断buffer是否为字符或数字,若是,则alphatp[1]=buffer;
3、重复1,2,直到2判断为假;在alphatp末尾添加’\0’;
4、调用search()子函数,在关键字表中匹配alphatp,若匹配成功,则返回序号;
5、调用search,在标识符表中匹配alphatp,若匹配成功,则返回序号;
6、在标识符表中添加alphatp,并返回序号;
(四)提示
数字和字符的判断利用库函数提供的isalpha()和(isdigit()
实验中用到的测试的 example.c的文件内容
///
#include <stdio.h>
void mian(){
int a=10,b=5;
if(a<b){
printf("a is smaller than b");}
else if(a>b){
printf("a is bigger than b");}
else{
do{
a=b+a;
b=a*b;
break;
}while(a==b)
}
return 0;
}/
代码
#include <iostream>
#include <string>
using namespace std;
#define MAX 22
char ch = ' ' ;
string key[15]={ "begin" , "end" , "if" , "then" , "else" , "while" , "write" , "read" ,
"do" , "call" , "const" , "char" , "until" , "procedure" , "repeat" };
int Iskey(string c){ // 关键字判断
int i;
for (i=0;i<MAX;i++) {
if (key[i].compare(c)==0) return 1;
}
return 0;
}
int IsLetter( char c) { // 判断是否为字母
if (((c<= 'z' )&&(c>= 'a' ))||((c<= 'Z' )&&(c>= 'A' ))) return 1;
else return 0;
}
int IsDigit( char c){ // 判断是否为数字
if (c>= '0' &&c<= '9' ) return 1;
else return 0;
}
void analyse(FILE *fpin){
string arr= "" ;
while ((ch=fgetc(fpin))!=EOF) {
arr= "" ;
if (ch== ' ' ||ch== '\t' ||ch== '\n' ){}
else if (IsLetter(ch)){
while (IsLetter(ch)||IsDigit(ch)) {
if ((ch<= 'Z' )&&(ch>= 'A' )) ch=ch+32;
arr=arr+ch;
ch=fgetc(fpin);
}
fseek(fpin,-1L,SEEK_CUR);
if (Iskey(arr)){cout<<arr<< "\t$ 关键字 " <<endl;}
else cout<<arr<< "\t$ 普通标识符 " <<endl;
}
else if (IsDigit(ch)){
while (IsDigit(ch)||ch== '.' &&IsDigit(fgetc(fpin))){
arr=arr+ch;
ch=fgetc(fpin);
}
fseek(fpin,-1L,SEEK_CUR);
cout<<arr<< "\t$ 无符号实数 " <<endl;
}
else switch (ch){
case '+' :
case '-' :
case '*' :
case '=' :
case '/' :cout<<ch<< "\t$ 运算符 " <<endl; break ;
case '(' :
case ')' :
case '[' :
case ']' :
case ';' :
case '.' :
case ',' :
case '{' :
case '}' :cout<<ch<< "\t$ 界符 " <<endl; break ;
case ':' :{ch=fgetc(fpin);
if (ch== '=' ) cout<< ":=" << "\t$ 运算符 " <<endl;
else {cout<< "=" << "\t$ 运算符 " <<endl;;
fseek(fpin,-1L,SEEK_CUR);}
} break ;
case '>' :{ch=fgetc(fpin);
if (ch== '=' ) cout<< ">=" << "\t$ 运算符 " <<endl;
if (ch== '>' )cout<< ">>" << "\t$ 输入控制符 " <<endl;
else {cout<< ">" << "\t$ 运算符 " <<endl;
fseek(fpin,-1L,SEEK_CUR);}
} break ;
case '<' :{ch=fgetc(fpin);
if (ch== '=' )cout<< "<=" << "\t$ 运算符 " <<endl;
else if (ch== '<' )cout<< "<<" << "\t$ 输出控制符 " <<endl;
else if (ch== '>' ) cout<< "<>" << "\t$ 运算符 " <<endl;
else {cout<< "<" << "\t$ 运算符 " <<endl;
fseek(fpin,-1L,SEEK_CUR);}
} break ;
default : cout<<ch<< "\t$ 无法识别字符 " <<endl;
}
}
}
void main(){
char in_fn[30];
FILE * fpin;
cout<< " 请输入源文件名(包括路径和后缀名) :" ;
for (;;){
cin>>in_fn;
if ((fpin=fopen(in_fn, "r" ))!=NULL) break ;
else cout<< " 文件路径错误!请输入源文件名(包括路径和后缀名) :" ;
}
cout<< "\n******************** 分析如下 *********************" <<endl;
analyse(fpin);
fclose(fpin);
cout<<endl;
cout<< " 按任意键结束 " <<endl;
int a;
cin>>a;
}
实验结果