if(!
strcmp(s,reservedWords[i].str))
returnreservedWords[i].tok;returnID;
2.getToken代码设计说明:
1)以状态表为驱动,根据当前的状态以及当前字符来决定下一个状态。
2)嵌套case通过一个状态标记来标记当前DFA所处的状态,通过
case分支语句来执行每一个转移的情况,直观易懂,但是随着DFA
状态数量的增多,循环嵌套的程序代码就会变得很冗长。
3)实现DFA的核心代码及分析:
扫描程序的主函数为getToken,用的是嵌套case的方法,通过自定义一个状态枚举类型来标记当前所处
的DFA状态,并用字符数组tokenString来保存已经扫描过的字符,每次调用getToken函数的时候,当前状态都会被初始化为START状态,用while循环当当前状态不为DONE状态,就从输入流获取一个字符,并根据上面给出的DFA判断如何进行状态转移;当当前状态为接收状态时,tokenString里面就是一个完整的token,于是将tokenString的内容打印到listing文件并返回tokenString里面的内容。
getToken函数调用getNextChar函数获取源文件中下一个字符,如果某些状态需要回溯一个字符,则调用ungetNextChar函数将已
经获取的字符释放出来等待下一个状态中重新获取。
GetToken函数中识别toker关键代码:
TokenTypegetToken(void){
inttokenStringIndex=0;
TokenTypecurrentToken;
StateTypestate=START;
intsave;
while(state!
=DONE)
{intc=getNextChar();
save=true;
switch(state)
{caseSTART:
if(isdigit(c))
{
state=INNUM;}
elseif(isalpha(c))
state=INID;
elseif(c=='!
')
state=INNE;
elseif(c=='=')
state=INEQ;
elseif(c=='>')
state=INRT;
elseif(c=='<')
state=INLT;
elseif(c=='/')
state=INOVER;
elseif((c=='')||(c=='\t')||(c=='\n'))
{
save=false;
//state=START;
}
else
{
state=DONE;
switch(c)
{caseEOF:
save=false;currentToken=ENDFILE;break;
case'+':
currentToken=PLUS;break;
case'-':
currentToken=MINUS;break;
case'*':
currentToken=TIMES;break;
case';':
currentToken=SEMI;break;
case',':
currentToken=COMMA;break;
case'(':
currentToken=LPAREN;break;
case')':
currentToken=RPAREN;break;
case'[':
currentToken=LZ;break;
case']':
currentToken=RZ;break;
case'{':
currentToken=LD;break;
case'}':
currentToken=RD;break;
default:
currentToken=ERROR;break;
}
}
break;
caseINNE:
state=DONE;
if(c=='=')
currentToken=NE;
else
{ungetNextChar();
save=false;currentToken=ERROR;
}
break;
caseINEQ:
state=DONE;
if(c=='=')
currentToken=EQ;
else
{ungetNextChar();currentToken=ASSIGN;
}
break;
caseINRT:
state=DONE;
if(c=='=')
currentToken=RTE;
else
{ungetNextChar();currentToken=RT;
}
break;
caseINLT:
state=DONE;
if(c=='=')
currentToken=LTE;
else
{ungetNextChar();
currentToken=LT;
}
break;
caseINNUM:
if(!
isdigit(c))
{ungetNextChar();save=false;state=DONE;
currentToken=NUM;
break;
caseINID:
if(!
isalpha(c))
{
ungetNextChar();
save=false;state=DONE;
}
currentToken=ID;break;
caseINOVER:
if(c=='*')
{
save=false;
state=INCOMMENT1;tokenStringIndex=0;
//currentToken=LC;
}
else
{
ungetNextChar();save=false;state=DONE;currentToken=OVER;
}
break;
caseINCOMMENT1:
if(c=='*'){
save=false;
state=INCOMMENT2;
}
elseif(c==EOF){save=false;state=DONE;currentToken=ERROR;
}
else
{
save=false;
state=INCOMMENT1;//currentToken=ENDFILE;
}
break;
caseINCOMMENT2:
save=false;
if(c==7'){
state=START;
}
elseif(c==EOF)
{state=DONE;currentToken=ERROR;}
elseif(c=='*')
{
state=INCOMMENT2;
}
else
{
state=INCOMMENT1;
}
break;
caseDONE:
default:
fprintf(listing,"ScannerBug:
state=%d\n”,state);state=DONE;
currentToken=ERROR;
break;
}
五、测试结果
测试小程序:
kelly.txt
1
+-*/
□+b-2+z;
inta(intbFintc[])<
if(a+b==c)d=e[1+2];
r色turn0;
-ti&CMnp(u312sIQDwl«lt
quuEflu气AIllklp右onpunLmsEM
常uuEflll片AIII
“p£onporul2W2N:
7S0Au-H'q4匚T〉祐4U-I-I"9
wHr-lfln
AnEal
VECE
£=召出#姙
name=a
n^ne=b
name=c
暂11辽务狂隽仃9:
S8888008S8
'第
d=ell*21;
ID,name-d
=
ID-nane-e[
NUM,ual=l
+
nun,u^i=2
]
■
return0;^9fy:
r-eser-ueduor-d=return第谕亍:
NUM,ual=0
當诰:
;
10=>
诰按柱意键继黒・・
程序运行结果分析:
如上图所示:
通过观察分析,发现程序已经能够成功识别关键字,如第-
行的“T,能成功识别出NUM,如第六行的“int”,成功识别出reservedword等。
另外,第三行为注释部分,已经被识别出并跳过。
同时,第四行为空,跳过。
通过以上实例运行结果可以得知,源文件中的各种token无论正确与否,
都能够被本扫描程序准确的扫描出来。
当能够获取正确的token时,就输出
token;当遇到不能识别的token时,就输出一个ERROR:
token;当遇至U注释的时候,就说明是注释,并绕过。
程序运行成功,词法分析正确。
六、小结
通过g本次实验,我学会了根据目标语言的词法规则构造正则表达式,并通过正则表达式构造出对应的DFA,并用代码实现DFA,能够用DFA来对C-语言进行词法分析。
更深入的理解了DFA的精髓,了解了用代码实现DFA的各种方法以及它们各自的特点。
同时,也深入理解并实践了编译原理词法分析的相关理论。
实验二:
C-语言词法分析器的lex生成
一、实验目的及意义
1.实现基于Lex的C-语言的词法分析器
2.学会安装ParserGenerator2并且熟悉其环境
3.熟练配置MicrosoftVisualC++6.0,并实现与ParserGenerator2相应库的连接
4.学习基于Lex构造词法分析器的方法,以及实验过程
5.熟悉C-语言的各种Token
6.构造各种Token的正则表达式
7.设计词法分析器所需要的各种数据结构及Token识别成功后的动作
8.用ParserGenerator实现所设计的C-词法分析器
、实验环境
1.WindowsXP操作系统
2.编译环境ParserGenerator
3.VC6.0开发环境
三、分析与设计
1.C语言的词法规则
(1)关键字
elseifintreturnvoidwhile
(2)特殊符号
+-*/<<=>>===!
==;,()[]{}/**/
(3)其它token(区分大小写)
ID=letterletter*
NUM=digitdigit*
letter=a|…|z|A|...|Z
Digit=0|…|9
(4)空白符号空白\n\t
(5)注释
由标记符号/*…*/标记起来的部分。
2.C语言的词法正则表达式设计
keyWord,SpecialChar,ID,ErrorlD,Num,Annotation,Whitespace,Enter,End,Other
相关正则表达式如下所示:
KeyWordelse|if|int|return|void|while
SpecialChar"+"|"_"|"*"「7"|"<"|"<="|">"|">="|"=="|
letter[A-Za-z]
digit[0-9]
ID{letter}{letter}*
ErrorID
{digit}+{letter}+({digit}|{letter})*|{letter}+{digit}+({digit}|{letter})*Num{digit}+
Annotation"/*"
Whitespace[\t]+
3.Erro的处理
KtyVcrd|ifiutxeturrLvcLdl
Spec!
alChau•八|t二・「"|匕二・「二二“|二•-m盯“|%“「尸
[0-?
1
ID{1sttbt]-£leztar)*
ErrorID[digitF+{latterH(血”町I{1etWEh)*HlexterJfld-igitJf(tdigicjI{letter}j・Num(di
Etid:
cE3Fi->
OtLez
四、测试结果输出
测试小程序
test.txt
intmain(intij
{
tnt口臣町;
intk23GD;/*ErrorTD6/
whiLfi(t-{
i++;
}
return0;
输出结果:
:
lxne
1:
KeyUovd.
±nt
1zLn记
1
ID
tneiin
1xne
d.
£peci.-alCh-ai*
c
line
1
KeyWoi^d.
±nt
1d_ne
1
ID
_g
l£ne
1
SpecialGh-ar
line
2
SpecieilCliaLi*
<
1zLoe
3
Ke
int
1±nc
3
ID
a.
line
3
Spec
L
江xne
3
Hum
50
xne
3
SliecietlGliar-
J
1£rte
3
SpHCiAiCtlSLi'
3
|工
4
Ke
±n"t
fline
仪
Erroi'ID:
R23GD
;line
4:
£peci^i.ACIiSi.1*
9
1xne
g跳过注釋
1ine
4:
S;p皂c:
i_0!
_Ch§r*
l±r>e
4-±-si±Cli-a.^
〜/3
1Ine
5;
:
KeyWor-d.
viliile
1ine
5:
SpeciAiCliAi*
il
£=IP
■
1
$工xne
5:
Specx-^TCli-aii^
<
■
1
;l±ne
11ine
1±ne
il±ne
1d_ne
1inc
1xnt*line
1±ne
1xne
隔到
FOFf
ID
SpecialChai*Speci-alCykai-SpecialGbarSpeciailCBfifci*EeyWovd
Num
SpecialChar-
vetuvn
实验结果分析:
如上图黄色部分所示,程序已经能够成功识别keyword,ID,NUM,SpecialCh等
常规token类型,同时能识别出ErrorlD。
并能处理嵌套注释和文件末注释。
程序分析正确,运行成功
五、小结
通过lex词法分析,学会了pargen的环境配置与使用。
并对C-的正则表达式和lex的运行原理有一定的了解。
实验四:
C-语言语法分析器的手工构造
一、实验目的及意义
1•熟悉C-语言的语法规则;
2.使用上下文无关文法描述C-语言的语法规则;
3.设计语法分析器所需要的各种数据结构;
4.基于递归下降法实现C-语言的语法分析器,能够输入源程序,输出整个程序的语法树。
二、实验环境
1.WindowsXP
2.MicrosoftVisualC++6.0
三、算法分析与设计
(1)C-的BNF语法描述如下:
1.program->declaration-list
2.declaration-list->declaration-listdeclaration|declaration
3.declaration->var-declaration|func-declaration
4.var-declaration->type-specifieIrD;|type-specifierID[NUM];
5.type-specifier->int|void
6.fun-declaration->type-specifieIrD(params)compound-stmt
7.params->param-list|void
8.param-list->param-list,param|param
9.param->type-specifieIrD|type-specifierID[]
10.compound-stmt->{local-declarationsstatement-lis}t|empty
11.local-declarations->local-declarationsvar-declaration|empty
12.statement-list->statement->liststatement|empty
13.statement->expression-stmt|compound-stmt|selection-stmt|iteration-stmt|return-stmt
14.expression-stmt->expressio;n|;
15.selection-stmt->if(expression)statement|
if(expression)statementelsestatement
16.iteration-stmt->while(expression)statement
17.return-stmt->return;|returnexpression;
18.expression->var=expression|simple-expression
19.var->ID|ID[expression]
20.simple-expression->additvie-expressionrelopaddtive-expression|additiveexpression