词法分析器
词法分析程序构造原理与实现技术
任红 08281071 计科0803班
1. 实验目的
设计完成正则文法所描述的Pascal 语言子集单词符号的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即关键字、其他标识符、整型常数、运算符、界符五大类。并在文本文件中依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。
2. 实验要求
1) 给出各单词符号的类别编码;
2) 词法分析程序应能发现输入串中的错误;
3) 词法分析作为单独一遍编写,词法分析结果为二元式序列组成的中间文件;
4) 设计两个测试用例(尽可能完备),并给出测试结果。 3. 实验设计
1)待分析的简单语言的词法
(1) 关键字:
"begin","end","if","then","else","for","do","while","and","or","not"
所有的关键字都是小写。
(2) 运算符和界符:
<, <=, <>, =, >, >=, :, :=, /, /*, +, -, *, ;, (, ), /* */
3) 其他单词是标识符(ID)和整型常数(NUM),通过以下正规式(
定义:
ID=letter(letter|digit)*
NUM=digit digit*
(4) 空格由空白、制表符和换行符组成。空格一般用来分隔ID、
1
NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2) 各种单词符号对应的种别码
表1 各种单词符号对应的种别码
单词符号 种别码 单词符号 种别码
begin 1 <> 16
end 2 = 17
if 3 > 18
then 4 >= 19
else 5 : 20
for 6 := 21
do 7 / 22
while 8 /* 23
and 9 + 24
or 10 - 25
not 11 * 26
letter (letter | digit)* 12 ; 27
digit digit* 13 ( 28
< 14 ) 29
<= 15
3) 词法分析程序的功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列组成的中间文件。
其中:syn为单词种别码;
token为存放的单词自身字符串;
3. 词法分析程序的算法思想
算法的基本任务是从字符串表示的源程序中识别出具体独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
1)主程序示意图
主程序示意图如图1所示。其中初值包括如下两个方面:
2
置初值
调用扫描子程序
输出单词二元组
否
输入串结束,
是
结束
图1
(1)关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张
表格
关于规范使用各类表格的通知入职表格免费下载关于主播时间做一个表格详细英语字母大小写表格下载简历表格模板下载
中(称为
关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹
配的单词,则该单词为关键字,否则为一般标识符。关键字表为一
个字符串数组,其描述如下:
Char *rwtab[11]={"begin","end","if","then","else","for","do",
"while","and","or","not"};
(2)程序中需要用到的主要变量为syn,TOKEN。
2) 扫描子程序的算法思想
首先设置2个变量:TOKEN用来存放构成单词符号的字符串; syn
用来存放单词符号的种别码。
4. 程序测试
测试样例1
begin x := 9; if x>0 then x:=2*x+1/3;/*此行为测试程序!*/end# 测试结果(„#?字符用于标示字符串结束):
3
输出文本:
( 1,begin) ( 12,x) ( 21,:=) ( 13,9) ( 27,;) ( 3,if) ( 12,x) ( 18,>) ( 13,0) ( 4,then) ( 12,x)
( 21,:=) ( 13,2) ( 26,*) ( 12,x) ( 24,+) ( 13,1) ( 22,/) ( 27,;) ( 2,end) ( 0,# )
测试样例2
begin
a := 2;
b := 1;
''
&
if(a >= b)
then a :=3;
else
then b :=2;
end#
测试结果:
输出文本:
( 1,begin) ( 12,a) ( 21,:=) ( 13,2) ( 27,;) ( 12,b) ( 21,:=) ( 13,1) ( 27,;) error error error
( 3,if) ( 28,() ( 12,a) ( 19,>=) ( 12,b) ( 29,)) ( 4,then) ( 12,a) ( 21,:=) ( 13,3) ( 27,;)
( 5,else) ( 4,then) ( 12,b) ( 21,:=) ( 13,2) ( 27,;) ( 2,end) ( 0,# )
5. 心得体会
通过这次用C语言对词法分析程序的编制,回顾了C语言的编程方法,加
深了对词法分析原理的理解和词法分析的实现过程,掌握了编译程序的实现方法
和技术。
6(附录
源代码
#include
#include
#include
#include
char TOKEN[20]; /*用来存放单词词文中的各个字符*/
4
char *rwtab[11]={"begin","end","if","then","else","for","do","while","and","or","not"}; /*
定义保留字*/
int syn;
int n;
FILE*fp, *fpout;
void scanner()
{
int count=0;
int i;
char ch;
ch=fgetc(fp);
while(ch==' '||ch=='\t'||ch=='\n') ch=fgetc(fp); /*当是空格、空白和换行的时候指向下
一个字符*/
if(isalpha(ch)) /*ch是字母字符时*/
{
TOKEN[0]=ch;
ch=fgetc(fp);i=1;
while(isalnum(ch))
{
TOKEN[i]=ch;i++;
ch=fgetc(fp);
}
TOKEN[i]='\0';
fseek(fp,-1,1);
syn=12; /*首先是将全部字母字符归为一类,syn=12*/
for(n=0;n<11;n++)
{
if(strcmp(rwtab[n],TOKEN)==0) /*判断字母字符是否是关键字*/
{
syn=n+1; /*如果是关键字,把相应的种别码给syn*/
}
}
}
else
if(isdigit(ch)) /*ch是数字字符时*/
{
TOKEN[0]=ch;
ch=fgetc(fp);i=1; /*对变量进行初始化*/
while(isdigit(ch))
{
TOKEN[i]=ch;i++;
ch=fgetc(fp);
}
5
TOKEN[i]='\0';
fseek(fp,-1,1);
syn=13;
}
else
switch(ch)
{
case'<':TOKEN[0]=ch;ch=fgetc(fp); /*当开始字符是„*/
if(ch=='=') /*当字符是<=时*/
{
TOKEN[1]=ch;
ch=fgetc(fp);
TOKEN[2]='\0';
fseek(fp,-1,1);
syn=15;
}
else if(ch=='>') /*当字符是<>时*/
{
TOKEN[1]=ch;
ch=fgetc(fp);
TOKEN[2]='\0';
fseek(fp,-1,1);
syn=16;
}
else /*当字符是<时,并返回上一字符*/
{
fseek(fp,-1,1);
syn=14;
}
break;
case'=':syn=17;TOKEN[0]=ch;break;
case'>':TOKEN[0]=ch;ch=fgetc(fp); /*当开始字符是„>?时
再分为几种情况:>,>=*/
if(ch=='=')
{
TOKEN[1]=ch;
ch=fgetc(fp);
TOKEN[2]='\0';
fseek(fp,-1,1);
syn=19; /*当字符是>=时*/
}
else
{
6
fseek(fp,-1,1);
syn=18;
}
break;
case':':
TOKEN[0]=ch;ch=fgetc(fp); /*当开始字符是„:?时再分为几
种情况::,:=*/
if(ch=='=') /*当字符是:=时*/
{
TOKEN[1]=ch;
ch=fgetc(fp);
TOKEN[2]='\0';
fseek(fp,-1,1);
syn=21;
}
else
{
syn=20;
fseek(fp,-1,1);
}
break;
case'/':
TOKEN[0]=ch;ch=fgetc(fp); /*当开始字符是„/?时再分为几
种情况:/,/* */
if(ch=='*') /*当字符是/*时*/
{
TOKEN[1]=ch;
ch=fgetc(fp);
i=2;
while(ch != '#'){
if(ch == '*'){
TOKEN[i]=ch;
i++;
ch=fgetc(fp);
if(ch == '/'){
TOKEN[0]='\0?;
break;
}
}
else{
syn=23;
ch=fgetc(fp);
TOKEN[2]='\0';
fseek(fp,-1,1);
7
}
}
ch=fgetc(fp);
TOKEN[i]='\0';
fseek(fp,-1,1);
}
else
{
syn=22;
ch=fgetc(fp);
TOKEN[1]='\0';
fseek(fp,-1,1);
}
break;
case'+':TOKEN[0]=ch; /*当字符是+时*/
TOKEN[1]='\0';
syn=26;break;
case'-':TOKEN[0]=ch; /*当字符是-时*/
TOKEN[1]='\0';
syn=27;break;
case'*':TOKEN[0]=ch; /*当字符是*时*/
TOKEN[1]='\0';
syn=28;break;
case';':TOKEN[0]=ch; /*字符是;时*/
TOKEN[1]='\0';
syn=29;break;
case'(':TOKEN[0]=ch; /*当字符是(时*/
TOKEN[1]='\0';
syn=30;break;
case')':TOKEN[0]=ch; /*当字符是)时*/
TOKEN[1]='\0';
syn=31;break;
case'#':TOKEN[0]=ch; /*当字符是#时*/
TOKEN[1]='\0';
fseek(fp,-1,1);
syn=0;
break;
default:syn=-1;
}
return;
}
int main()
{
fp=fopen("fp.txt","r");
8
if(!fp)
{
printf("file cannot be opened!");
}else
{
do
{
FILE *fpout;
scanner();
switch(syn)
{
case -1: fpout= fopen( "output.txt", "w" );fprintf( fpout, "\n
error\n");fclose(fpout);break;
default: fpout= fopen( "output.txt", "w" );fprintf( fpout, "( %d,%s )
\n",syn,TOKEN );fclose(fpout);
}
}while(syn!=0);
}
system("pause");
return 0;
}
9