一、词法分析简介
词法分析阶段是编译过程的第一个阶段,是编译的基础。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。词法分析程序实现这个任务。
词法分析是编译程序的第一个阶段且是必要阶段;词法分析的核心任务是扫描、识别单词且对识别出的单词给出定性、定长的处理;实现词法分析程序的常用途径:自动生成,手工生成。
完成词法分析任务的程序称为词法分析程序或词法分析器或扫描器。
从左至右地对源程序进行扫描,按照语言的词法规则识别各类单词,并产生相应单词的属性字。
二、设计要求
创建一个词法分析程序,它支持对正规文法的分析。必须使用DFA(确定性有限自动机)或NFA(非确定性有限自动机)来实现这一项目。该程序的输入是一个文本文件,包括一组由该正规文法产生的产生式以及待识别源代码字符串。该程序的输出是一个符号表(二元式),它由5种类型符号:关键词,识别符,常量,界符和操作符。
三、开发环境
硬件环境:PC机 windows10 64 位
编程语言:C++
运行环境:codeblocks或vs
四、实现过程
用子集法将NFA转化为DFA。具体实现是:做一个NFA_set类型的栈,新状态不停的进栈,每次从堆栈中弹出一个,计算其转换的结果,是新状态就进栈,重复则丢弃,只记录好dfa的转换,直到栈空。最后成功构造出DFA。
对输入源程序的扫描过程很简单,一次读入一个字符,成串的送入匹配和DFA判断其合法性。给出输出结果。
五、分析过程框架图
六、运行结果
识别程序的一部分输出结果:
对应的用于语法分析的部分输入:
七、部分核心代码
void NFA_to_DFA()
{
num_new_set=0;
NFA_set work_set;
NFA_set worked_set;
work_set.set[work_set.len++]=start;
worked_set.len=0;
stack<NFA_set> s;
get_closure(work_set);
s.push(work_set);
new_set[num_new_set++]=work_set;
for(int i=0;i<150;++i)
{
for(int j=0;j<150;++j)
{
dfa[i][j]='-1';
}
}
for(int i=0;i<150;++i)
is_final[i]=false;
if(Is_contained_Y(work_set))
is_final[num_new_set-1]=true;
while(!s.empty())
{
work_set=s.top();
s.pop();
for(int i=0;i<len_final;++i)
{
for(int j=0;j<work_set.len;++j)
{
for(int k=0;k<move[work_set.set[j]][final[i]].len;++k)
{
if(move[work_set.set[j]][final[i]].set[k]!='#' && move[work_set.set[j]][final[i]].set[k]!='Y' && !Is_in_set(move[work_set.set[j]][final[i]].set[k],worked_set))
{
worked_set.set[worked_set.len++]=move[work_set.set[j]][final[i]].set[k];
}
if(move[work_set.set[j]][final[i]].set[k]=='Y' && !Is_in_set(move[work_set.set[j]][final[i]].set[k],worked_set))
{
worked_set.set[worked_set.len++]='Y'; //用Y表示终态
}
}
}
get_closure(worked_set);
if(worked_set.len>0 && Is_in(worked_set)==-1)
{
dfa[num_new_set-1][final[i]]=num_new_set;
s.push(worked_set);
new_set[num_new_set++]=worked_set;
if(Is_contained_Y(worked_set))
{
is_final[num_new_set-1]=true;
}
}
if(worked_set.len>0 && Is_in(worked_set)>-1 && final[i]!='@')
{
dfa[Is_in(work_set)][final[i]]=Is_in(worked_set);
}
worked_set.len=0;
}
}
}