有了上一篇文章中的构建块,实现词法分析器不再困难。
我们先回顾一下各个模块:
然后我们尝试将它们组装起来,因为一开始实现的都是零件(子功能)。本文主要介绍main函数中运行的自动机。
还记得第-1条中的DFA吗?
在第0 部分并满足问题要求之后,我们最终的DFA 应如下所示:
流程大致如下:
根据上述思路,经过不断调试和改进,主要功能设计为:
int main(){ 初始化();字符串tmp;字符c; while((c=getchar()) !=EOF) { if(isspace(c)) //忽略空白继续; if(isdigit(c)) //如果以数字开头{ ungetc(c, stdin); cout '数字:' num() endl;继续; } 字符查看;查看=getchar(); //前进一步if((c=='+' | | c=='-') isdigit(peek)) //输入有符号数{ ungetc(peek, stdin); ungetc(c, 标准输入); cout '数字:' num() endl;继续; } if(c=='/' peek=='*') //输入评论{ cout 'COMMENTS : /*' comments() endl;继续; } int tkn=0;字符串s; if(!isalnum(c)) //输入c 是一个特殊符号{ s +=c; if(peek=='=') //仅定义=的第二个二元运算符可以是惰性的; s +=偷看;否则ungetc(peek, stdin) ; tkn=查询; } if(!tkn){ //如果不是以特殊符号开头,则以字母开头ungetc(peek, stdin); s+=c; while((c=getchar()) !=EOF) //读取这串字母{ if(isspace(c)) break; if(isalnum(c) || c=='_') s +=c;否则{ ungetc(c, stdin);休息; } } tkn=查询; //查询token } switch (tkn) //根据token 打印{ case 1: cout 'KEYWORD : ' s endl;休息; case 2: cout 'BASIC :' s endl;休息; case 3: cout 'IDENTITY :' s endl;休息; case 5: cout 'SYMBOL :' s endl;休息;默认:中断; } } 返回0;} 测试
使用测试示例1:
{ /* 一个例子*/int i,j;浮动x;浮动[100]一个; while ( true) { do i=i + 1; while (a[i] x); if ( i=j ) 中断; x=a[i]; } }输出结果:
//第1 行{ /* 示例*/SYMBOL : {COMMENTS : /* 示例*///第2 行int i,j;浮动x; float[100] a;BASIC : intIDENTITY : iSYMBOL :IDENTITY : jSYMBOL :BASIC : floatIDENTITY : xSYMBOL :(关键字: trueSYMBOL : )SYMBOL 3336 0 {//第4 行do i=i + 1; while ( a[i] x);关键字: doIDENTITY : iSYMBOL :=IDENTITY : iSYMBOL : +数字: 1SYMBOL :关键字: whileSYMBOL : (IDENTITY : aSYMBOL : [IDENT ITY : iSYMBOL :]SYMBOL :=j ) 中断;关键字: ifSYMBOL : (IDENTITY : iSYMBOL :=IDENTITY : jSYMBOL : )KEYWORD : breakSYMBOL ://第6 行x=a[i];IDENTITY : xSYMBOL :=IDENTITY : aSYMB OL : [IDENTITY : iSYMBOL :]SYMBOL ://line 7 }SYMBOL : }//line 8 }SYMBOL : } 可以发现输出结果完全正确。
测试示例2:测试编号
+1212.551e1589 输出:
DIGIT : +1212.551e1589好了,现在,我们已经完成了这个实验任务,设计一个简单的词法分析器。在设计过程中,我们使用了Trie树数据结构,使得代码变得更加美观。同时,针对更复杂的数字阅读行为,我们设计了由DFA确定的有限状态自动机来完成。最后我们在main函数中将它们拼接在一起,就形成了最终的词法分析器。整个实验花了半天时间,整体思路不难理解。我相信如果你从头读完这篇文章,逻辑就会很清楚。