词法分析---基于Asp.NET(实验二学习笔记)
2012-10-16 00:42
260 查看
一、背景
任务说明
词法分析表保留字 | 特殊符号 | 其他 |
If | + | 十进制的整数与实数 |
else | - | |
while | * | |
read | / | 标识符(由数字、字母和下划线组成的串,但必须以字母开头、且不能以下划线结尾的串) |
write | = | |
int | < | |
real | == | |
<> | ||
( | ||
) | ||
; | ||
{ | ||
} | ||
/* | ||
*/ | ||
[ | ||
] |
二、 功能实现描述
正则表达式
在cmm中,语言记号大致可分为以下几大类。1. 保留字
在正则表达式中,保留字是最简单的了,因为它们仅是由字符的固定序列表示,如果要将所有的保留字收集到一个定义中,就可以写成:
Reserved=int|real|if|else|while|read|write…….
2. 数
数可以是数字(自然数)、十进制数、或者是小数
Nat=[0-9]+
signedNat=(+|-)nat
float=singedNat ”.” Nat
3. 标识符
标识符不是固定的字符串。在cmm中,规定标识符必须由一个字母开头并且只包括字母和数字。可以用一下正则表达式:
Letter=[a-zA-Z]
Digit=[0-9]
Identifier=letter(letter|digit)*
4. 注释
注释在扫描过程中是被忽略的, 扫描程序必须注释并舍弃它们。虽然扫描程序可能没有清晰的常量记号,但是仍需要给注释编写出正则表达式。在cmm中,我给出的单行注释是://,多行注释有:/* */或{}
5. 二义性、空白格和先行
在使用正则表达式的描述中,有一些串经常可以被不同的正则表达式匹配。例如:if和while的串可以既是标识符又可以是关键字。程序设计语言定义规定了应遵守哪个解释,但是正则表达式本身却无法做到它。相反地,语言定义必须给出无二义性规则,由其回答每一种情况下的含义。
程序设计语言中空白格伪记号的典型定义是:
Whitespace=(newline|blank|tab|comment)+
其中,等号右边的标识符代表恰当的字符或串。空白格通常不是作为记号分隔符,而是被忽略掉。
分隔符结束记号串,但他们并不是记号本身的一部分。因此,扫描程序必须处理先行(lookahead)问题:当它遇到一个分隔符时,它必须做出安排分隔符不会从输入的其他部分中国删除,方法是将分隔符返回到输入串或在将字符从输入中删除之前先行。在大多数情况下,只有单个字符才需要这样做(“单个字符先行”)。
有穷自动机
有穷自动机,或称有穷状态的机器,是描述特定类型算法的数学方法。特别地,有穷自动机可用作描述在输入串中识别模式的过程,因此也能用作构造扫描程。当然有穷自动机与正则表达式之间有着很密切的关系。确定性有穷自动机(DFA)定义:一个确定的有穷自动机(DFA)M是一个五元组:M=(K,Σ,f,S,Z)其中
① K是一个有穷集,它的每个元素称为一个状态;
② Σ是一个有穷字母表,它的每个元素称为一个输入符号,所以也称Σ为输入符号字母表;
③ f是转换函数,是K×Σ→K上的映射,即,如 f(ki,a)=kj,(ki∈K,kj∈K)就意味着,当前状态为ki,输入符为a时,将转换为下一个状态kj,我们把kj称作ki的一个后继状态;
④ S ∈ K是唯一的一个初态;
⑤ Z⊂K是一个终态集,终态也称可接受状态或结束状态。
DFA的下一个状态有当前状态和当前输入字符唯一给出的自动机。非确定的有穷自动机是由它产生的。
带有出错转换的标识符的有穷自动机
以上给出了带有出错转换标识符的有穷自动机的示例图。Nat和小数的DFA非常简单,在这里就不给出示例了。CMM词法分析器的DFA:
从正则表达式到DFA
我们只关心两个算法:一个是将正则表达式翻译成NFA,另一个是将NFA翻译成DFA。再将DFA翻译成程序。程序 |
DFA |
NFA |
正则表达式 |
实现DFA的主要代码:
publicstatic TokenTypegetToken()
{
inttokenStringIndex = 0;/*
当Ì¡À前¡ãtoken的Ì?索¡Â引°y
*/
/* 当Ì¡À前¡ãtoken的Ì?类¤¨¤型¨ª*/
TokenTypecurrentToken =
TokenType.VOID; ;
/* 起e始º?状Á¡ä态¬?
*/
StateTypestate =
StateType.START;
/* 标À¨º识º?是º?否¤?储ä¡é存ä?当Ì¡À前¡ã字Á?符¤?
*/
intsave;
int once=1;
while(state !=
StateType.DONE)
{
intc = getNextChar();
save = 1;
switch(state)
{
caseStateType.START:
if(Char.IsNumber((char)c))
state = StateType.INNUM;
elseif(c=='.')
state = StateType.POINT;
elseif (Char.IsLetter((char)c))
state = StateType.INID;
// else if (c == ':')
// state = INASSIGN;
elseif (c ==
'<')
state = StateType.INLESS;
elseif (c ==
'>')
state = StateType.INGREAT;
elseif (c ==
'=')
state = StateType.INASSIGN;
elseif (c ==
'!')
state = StateType.INNEQUAL;
elseif(c==
'/')
{
save=0;
state = StateType.INCOMMENT2;
}
elseif ((c ==
' ')|| (c == '\t') || (c ==
'\n'))
save = 0;
// else if (c == '{')
// { save = FALSE;
// state = INCOMMENT;
// }
else
{
state = StateType.DONE;
switch (c)
{
case -1://文?件t结¨¢束º?
save = 0;
currentToken =
TokenType.ENDFILE;
break;
case'{':
currentToken =
TokenType.LBEGIN;
break;
case
'}':
currentToken =
TokenType.REND;
break;
case
'+':
currentToken =
TokenType.PLUS;
break;
case
'-':
currentToken =
TokenType.MINUS;
break;
case
'*':
currentToken =
TokenType.TIMES;
break;
// case '/':
// currentToken = OVER;
// break;
case
'(':
currentToken =
TokenType.LPAREN;
break;
case
')':
currentToken =
TokenType.RPAREN;
break;
case'[':
currentToken =
TokenType.LARRAY;
break;
case
']':
currentToken =
TokenType.RARRAY;
break;
case
';':
currentToken =
TokenType.SEMI;
break;
case',':
currentToken =
TokenType.COMMA;
break;
case'%':
currentToken =
TokenType.MOD;
break;
default:
currentToken =
TokenType.ERROR;
break;
}
}
break;
caseStateType.INCOMMENT:
save = 0;
if(c == -1)
{
state = StateType.DONE;
currentToken =
TokenType.ENDFILE;
}
elseif (c ==
'}')state = StateType.START;
break;
caseStateType.INLESS:
state = StateType.DONE;
if(c ==
'=')
currentToken =
TokenType.LE;
elseif (c ==
'>')
currentToken =
TokenType.NEQ;
else
{ /*取¨?备À?份¤Y的Ì?前¡ã一°?个?字Á?符¤?
*/
ungetNextChar();
save = 0;
currentToken =
TokenType.LT;
}
break;
caseStateType.INGREAT:
state = StateType.DONE;
if(c ==
'=')
currentToken = TokenType.GE;
else
{ /*backup in the input */
ungetNextChar();
save = 0;
currentToken =
TokenType.GT;
}
break;//INNOEQUAL
caseStateType.INASSIGN:
state = StateType.DONE;
if(c ==
'=')
currentToken = TokenType.EQ;
else
{
ungetNextChar();
save = 0;
currentToken = TokenType.ASSIGN;
}
break;
caseStateType.INNEQUAL:
state = StateType.DONE;
if(c ==
'=')
currentToken = TokenType.NEQ;
else
{
ungetNextChar();
save = 0;
currentToken = TokenType.ERROR;
}
break;
caseStateType.INCOMMENT2:
save = 0;
if(c == -1)
{
state = StateType.DONE;
currentToken =
TokenType.ENDFILE;
}
elseif (c ==
'/')
{
state = StateType.INCOMMENT_SINGLE;
}
else
if(c=='*')
{
state = StateType.INCOMMENT_MULTI_1;
}
else
{
ungetNextChar();
save = 1;
c='/';
currentToken =
TokenType.OVER;
state = StateType.DONE;
}
break;
caseStateType.INCOMMENT_SINGLE:
save = 0;
if(c == -1)
{
state = StateType.DONE;
currentToken =
TokenType.ENDFILE;
}
elseif (c ==
'\n')
state = StateType.START;
break;
caseStateType.INCOMMENT_MULTI_1:
save = 0;
if(c == -1)
{
state = StateType.DONE;
currentToken =
TokenType.ENDFILE;
}
elseif (c ==
'*')
state = StateType.INCOMMENT_MULTI_2;
break;
caseStateType.INCOMMENT_MULTI_2:
save = 0;
if(c == -1)
{
state = StateType.DONE;
currentToken =
TokenType.ENDFILE;
}
elseif (c ==
'/')
state = StateType.START;
else
state = StateType.INCOMMENT_MULTI_1;
break;
caseStateType.POINT:
if(!Char.IsLetter((char)c))
{
ungetNextChar();
save = 0;
state = StateType.DONE;
currentToken =
TokenType.NUM;
}
break;
caseStateType.INNUM:
if(c=='.'&&once!=0)
{
--once;
break;
}
if(!Char.IsLetter((char)c))
{
ungetNextChar();
save = 0;
state = StateType.DONE;
if(once!=0)
currentToken =
TokenType.NUM;
}
break;
caseStateType.INID:
if(!Char.IsLetter((char)c)&&!Char.IsDigit((char)c))
{
ungetNextChar();
save = 0;
state = StateType.DONE;
currentToken =
TokenType.ID;
}
break;
caseStateType.DONE:
default:
state = StateType.DONE;
currentToken = TokenType.ERROR;
break;
}
if((save!=0) && (tokenStringIndex <= MAXTOKENLEN))
{
tokenString[tokenStringIndex] = (char)c;
tokenStringIndex++;
}
if(state ==
StateType.DONE)
{
tokenString[tokenStringIndex] =
'\0';
if(currentToken ==
TokenType.ID)
{
currentToken =reservedLookup(charToString(tokenString));
}
}
}
//util.printToken(currentToken,tokenString.ToString());
StringtempS =
Util.printToken(currentToken,charToString(tokenString));
objCode += " "+tempS;
returncurrentToken;
}
实现方法
本人采用Asp.NET,在windows 7平台下,将cmm语法解释器做成网页版的,在某种程度上实现了跨平台性。三、使用说明
由于我这Web项目无法打包成一个可以执行的文件,只可以在浏览器下访问,可能需要在VS2010下编译执行。在左侧方框中输入要分析的源文件,点击分析之后,在右侧方框出现词法分析。
四、参考资料
1.《编译原理及实践》 KennethC.Louden著2.百度百科http://baike.baidu.com/view/289418.htm#3
相关文章推荐
- Asp.Net Ajax 学习笔记12 基于Microsoft AJAX Library扩展客户端组件
- 【原创】Asp.net MVC学习笔记之-基于类型来绑定Model的属性
- ASP.Net学习笔记004--基于ashx方式的ASP.Net开发1
- [ASP.NET学习笔记之二十三]基于组件的程序设计
- 【原创】Asp.net MVC学习笔记之-基于用途来绑定Model的属性
- ASP.NET 3.5核心编程学习笔记(17):基于数据源的数据绑定
- Testing ASP.NET Applications_学习笔记V0.1
- ASP.NET 学习笔记
- ASP .Net学习笔记_20171115
- ASP.NET学习笔记[11] - Gridview里的下拉框筛选效果
- ASP.NET Core 2.0系列学习笔记-启动类Startup
- 黑马程序员之asp.net学习笔记:一般处理程序(*.ashx)小结
- Asp.net学习笔记----母板页结合CSS样式设计
- 黑马程序员之ASP.NET学习笔记: 分享Asp.net中具体的日期格式化用法
- <转>ASP.NET学习笔记之MVC 3 数据验证 Model Validation 详解
- Asp.net数据库SQL数据库操作学习笔记
- 【Pro ASP.NET MVC 3 Framework】.学习笔记.12.ASP.NET MVC3的细节:URLs,Routing和Areas
- Asp.net Ajax 学习笔记5 UpdatePanel的使用(下)
- asp.net 控件开发学习笔记(1)
- [ASP] asp.net学习笔记2