- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
void InputStr();//输入函数
void Output(int a,char *p1,char *p2);//输出函数
int IsAcceptantCharacter(char *p);//判断输入字符是否属于字符集
int IsOperator(char *p);//判断字符是否是字符集[+,-,*,/,(,)]中的字符
switch(ch)
{
case '+':
Output(PLUS,p,p);break;
case '-':
Output(SUBTRACT,p,p);break;
case '*':
Output(MULTIPLY,p,p);break;
case '/':
Output(DIVIDE,p,p);break;
case '(':
ptr1=a;
ptr2=a;
while(*ptr2!='\0')
{
j++;
if(!IsAcceptantCharacter(ptr2))
{
cout<<"\t您输入的第"<<j<<"个字符"<<*ptr2<<"不可以被此程序识别!"\
<<"将被跳过."<<endl;
ptr2++;
continue;
}
else
函数LOOKUP:每调用一次,就以TOKEN中的字符串查保留字表,若查到,就将相应关键字的类别码赋给整型变量c;否则将c置为零。
函数RETRACT:每调用一次,就把扫描指示器回退一个字符位置(即退回多读的那个字符)。
函数OUT:一般仅在进入终态时调用此函数,调用的形式为OUT(c,VAL)。其中,实参c为相应单词的类别码或其助记符;当所识别的单词为标识符和整数时,实参VAL为TOKEN(即词文分别为字母数字串和数字串),对于其余种类的单词,VAL均为空串。函数OUT的功能是,在送出一个单词的内部表示之后,返回到调用该词法分析程序的那个程序。
输出:对识别出的每一单词均单行输出其类别码(无符号数的值暂不要求计算)。
三、实现方法与环境
1、首先设计识别各类单词的状态转换图。
描述无符号常数的确定、最小化状态转换图如图1所示。其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>,1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。
char ch;
int i=0;
while((ch=cin.get())!='\n')
{
testStr[i]=ch;
i++;
}
AbnormityExamine(testStr);
}
void AccidenceAnalysis::AbnormityExamine(char a[])
{
int j=0;
char *ptr1,*ptr2;
return 0;
}
int AccidenceAnalysis::IsUnsignedNum(char *p)
{
char ch=*p;
if('0'<=ch&&ch<='9')
return 1;
else
return 0;
}
int AccidenceAnalysis::IsAcceptantCharacter(char *p)
源程序:
#include<iostream>
using namespace std;
#define M 101 //最多可输入的字符数
#define UNSIGNEDNUMBER 1 //无符号数
#define PLUS 2//加号
#define SUBTRACT 3//减号
#define MULTIPLY 4//乘号
单词符号
类别编码
类别码的助记符
单词值
begin
1
BEGIN
end
2
END
if
3
IF
then
4
THEN
else
5
ELSE
标识符
6
ID
字母打头的字母数字串
整常数
7
INT
数字串
<
8
LT
<=
9
LE
=
10
EQ
<>
11
NE
>
12
GT
>=
13
GE
:=
14
IS
+
15
PL
-
16
MI
*
17
MU
/
18
DI
处理过程:在此为了使词法分析程序结构比较清晰,且尽量避免某些枝节问题的纠缠,假定要编译的语言中,全部关键字都是保留字,程序员不得将它们作为源程序中的标识符;在源程序的输入文本中,关键字、标识符、整常数之间,若未出现关系和算术运算符以及赋值符,则至少须用一个空白字符加以分隔。作了这些限制以后,就可以把关键字和标识符的识别统一进行处理。即每当开始识别一个单词时,若扫视到的第一个字符为字母,则把后续输入的字母或数字字符依次进行拼接,直至扫视到非字母、数字字符为止,以期获得一个尽可能长的字母数字字符串,然后以此字符串查所谓保留字表(此保留字表已事先造好),若查到此字符串,则取出相应的类别码;反之,则表明该字符串应为一标识符。采用上述策略后,针对表2中部分单词可以构造一个如图2所示的有限自动机(以状态转换图表示)。在图2中添加了当进行状态转移时,词法分析程序应执行的语义动作。根据图2,可用C语言编写出符合以上几项要求的一个相应的扫描器程序,如程序一所示。
Output(LEFTBRACKET,p,p);break;
case ')':
Output(RIGHTBRACKET,p,p);break;
default:
break;
}
}
void AccidenceAnalysis::AssortIdentify()
{
while(*p!='\0')
{
if(IsOperator(p))
图1文法G[<无符号数>]的状态转换图
其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>,1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。
在一个程序设计语言中,一般都含有若干类单词符号,为此可首先为每类单词建立一张状态转换图,然后将这些状态转换图合并成一张统一的状态图,即得到了一个有限自动机,再进行必要的确定化和状态数最小化处理,最后据此构造词法分析程序。
{
char ch=*p;
if(IsOperator(p)||IsUnsignedNum(p)||ch=='E'||ch=='.')
return 1;
else return 0;
}
void AccidenceAnalysis::IdentifyOperator(char *p)
{
char ch=*p;
{
cout<<*p1;
p1++;
}
cout<<endl;
}
int AccidenceAnalysis::IsOperator(char *p)
{
char ch=*p;
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')')
return 1;
else
};
AccidenceAnalysis::AccidenceAnalysis()
{
int i;
for(i=0;i<M;i++)
testStr[i]='\0';
p=&testStr[0]; //指针P指向字符数组首元素
}
void AccidenceAnalysis::InputStr()
{
cout<<"\t请按要求输入您要分析的语句,所输字符应在要求范围(不超过"<<M<<")之内,并按回车键运行:";
实验一词法分析程序实现
一、实验目的与要求
通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验内容
选取无符号数的算术四则运算中的各类单词为识别对象,要求将其中的各个单词识别出来。
输入:由无符号数和+,-,*,/, ( , )构成的算术表达式,如1.5E+2-100。
{
IdentifyOperator(p++);
continue;
}
else if(IsUnsignedNum(p)||*p=='.')
{
char *p1=p;
if(IsUnsignedNum(p))
{
while(IsUnsignedNum(p))
p++;
if(*p=='\0')
{
Output(UNSIGNEDNUMBER,p1,--p);
#define DIVIDE 5//除号
#define LEFTBRACKET 6//左括号
#define RIGHTBRACKET 7//右括号
class AccidenceAnalysis //定义词法分析器类
{
private:
char testStr[M],*p;//私有数据
public:
AccidenceAnalysis();//构造函数
四则运算算术符号的识别很简单,直接在状态图的0状态分别引出相应标记的矢线至一个新的终态即可。根据自己的习惯,也可以将其转换为状态矩阵形式。
2、词法分析程序编写
根据描述语言中各类单词的文法状态转换图或状态矩阵,利用某种语言(C语言或JAVA语言)直接编写词法分析程序。
3、词法分析程序测试
用于测试扫描器的实例源文件中应有词法正确的,也应有错误的字符串,对于输入的测试用例的源程序文件,以对照的形式将扫描器的分析结果信息在输出文件中表示出来。
{
*ptr1=*ptr2;
ptr1++;
ptr2++;
}
}
while(ptr1<=ptr2)
{
*ptr1='\0';
ptr1++;
}Leabharlann Baidu
}
void AccidenceAnalysis::Output(int a,char *p1,char *p2)
{
cout<<"\t类别码:"<<a<<"单词值:";
while(p1<=p2)
p++;
continue;
}
else if(*p=='E')
{
p++;
if(IsUnsignedNum(p))
{
while(IsUnsignedNum(p))
p++;
Output(UNSIGNEDNUMBER,p1,--p);
p++;
continue;
}
else if(*p=='+'||*p=='-')
int IsUnsignedNum(char *p);//判断字符是否是0--9的整数
void AbnormityExamine(char a[]);
void IdentifyOperator(char *p);//识别字符集[+,-,*,/,(,)]中的字符
void AssortIdentify();//对输入字符分类识别
{
p++;
while(IsUnsignedNum(p))
p++;
Output(UNSIGNEDNUMBER,p1,--p);
p++;
continue;
}
}
else if(*p=='.')
{
p++;
while(IsUnsignedNum(p))
p++;
if(*p=='\0')
{
Output(UNSIGNEDNUMBER,p1,--p);
{
p++;
while(IsUnsignedNum(p))
p++;
Output(UNSIGNEDNUMBER,p1,--p);
p++;
continue;
}
}
else
p++;
continue;
}
else if(*p=='E')
{
p++;
if(IsUnsignedNum(p))
{
while(IsUnsignedNum(p))
p++;
Output(UNSIGNEDNUMBER,p1,--p);
p++;
continue;
}
else if(*p=='+'||*p=='-')
图2识别表I所列语言中的部分单词的DFA及相关函数
图2所出现的变量及函数的含义和功能说明如下:
函数GETCHAR:每调用一次,就把扫描指示器当前所指示的源程序字符送入字符变量ch,然后把扫描指示器前推一个字符位置。
字符数组TOKEN:用来依次存放一个单词词文中的各个字符。
函数CAT:每调用一次,就把当前ch中的字符拼接于TOKEN中所存字符串的右边。
四、参考资料
实现无符号数识别的参考方法:将设计的状态转换图直接转化为一张程序流程图,并在外层再增加一个以EOF为循环终止条件的while循环,即形成能连续识别各类单词的词法分析程序。
各类单词的编码建议如表1。
表1单词的内部编码
单词符号
类别码(CLASS)
单词值(VALUE)
无符号数
1
数字值
+
2
无值
-
3
无值
*
4
无值
/
5
无值
(
6
无值
)
7
无值
五、扩展实验
1、试对基础实验识别的单词种类进行扩充,构造识别以下单词的词法分析程序。
语言中具有的单词包括五个有代表性的关键字begin、end、if、then、else;标识符;整型常数;六种关系运算符;一个赋值符和四个算术运算符。参考实现方法简述如下。
表2扩展单词分类码表