2.2 一个简单的词法分析器示例

You might also like

Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 18

2.

2 一个简单的词法分析器示例

 2.2.1 C 语言子集的单词符号表示
 2.2.2 C 语言子集对应的状态转换图的设

 2.2.3 状态转换图的实现

21/10/29 1
2.2.1 C 语言子集的单词符号表示

大多数程序语言的单词符号
都可用状态转换图予以识别。下面构造
一个 C 语言子集的简单词法分析器,该
C 语言子集的所有单词符号及其种别编
码和内码值如下表所示。
由于直接使用整数编码不利于记忆
,故采用一些助记符表示种别编码。

21/10/29 2
表 2.1 C 语言子集的单词符号及内码值
单词符号 种别编码 助记符 内码值
while 1 while —
if 2 if —
else 3 else —
switch 4 switch —
case 5 case —
标识符 6 id id 在符号表中位置
常数 7 num num 在常数表中位置
+ 8 + —
− 9 − —
* 10 * —
<= 11 relop LE
< 11 relop LT
== 11 relop EQ
= 12 = —
; 13 ; —
21/10/29 3
2.2.2 C 语言子集对应的状态转换图的设计
首先对输入串做预处理。
即剔除多余的空格、注释、制表
符和换行符等。

其次把保留字作为一类特殊标识符处理。

即对保留字不专设对应的状态转
换图,当状态转换图识别出一个标识符时
就去查表,确定它是否为一个保留字。 4
21/10/29
 对保留字专设对应的状态转换图:

 C 语言子集对应的状态转换图如下:
21/10/29 5
空白 字母或数字
开始 字母 非字母数字
0 1 2 * 返回 (id, id 在符号表中位置 )
数字 或返回 (保留字 , -)
数字
3 4 * 返回 (num, num 在常数表中位置 )
非数字

5 返回 (+, -)
- 6 返回 (- , -)
* 7 返回 (*, -)

8 = 9 返回 (relop, LE)
其它
10 * 返回 (relop, LT)

11 = 12 返回 (relop, EQ)
其它
13 * 返回 (= , -)

14 返回 (; , -)
其它
21/10/29 15 * 非法字符错 6
注意 :
(1) 状态 2 识别出一个单词符号后需先
查保留字表 , 若匹配则为保留字 , 否则为标
识符。若为标识符 , 还需查符号表 , 看表中
是否有此标识符。若符号表中无此标识
符 , 则先将它登录到符号表中 , 再返回它在
符号表中入口地址作为内码值 ; 若表中有
此标识符 , 则直接返回其入口地址作为内
码值。
(2) 状态 4 识别出一个常数后可以将它
转换成二进制常数再登录到常数表 , 然后
返回它在常数表中的入口指针作为内码值7
21/10/29
2.2.3 状态转换图的实现
状态转换图易于用程序实现 , 最
简单的办法是让每个状态对应一小段程序。
对于图 2–5, 首先引进一组变量和过程:
(1)character: 字符变量 , 存放最新读入
的源程序字符。
(2)token: 字符数组 , 存放构成单词符号
的字符串。
(3)getbe( ): 若 character 中字符为空 , 则
调用 getchar( ), 直至 character
为非空。
21/10/29 8
(4)concatenation( ): 将 token 中字符串与
character 中字符连接作为 token 中的

字符串。
(5)letter( ) 和 digit( ): 判断 character 中
的字
符是否为字母和数字的布尔函数 ,
若是
则返回 true, 否则返回 false 。
(6)reserve( ): 按 token 数组中的字符串查
21/10/29 保留字表 , 若是保留字则返回其编 9
(7) retract( ): 扫描指针回退一个字符 , 同
时将 character 置为空白。
(8)buildlist( ): 将标识符登录到符号表或将常数
登录到常数表;若登录表中已存在该标识

或常数,则返回相关信息。
(9)error( ): 进行出错处理。
(10)getchar(): 把下一个输入字符读到 character
中,读入源程序字符的指针前移一个字符。
21/10/29 10
C 语言子集对应的的词法分析器如下 :
token= ' '; /* 对 token 数组初始化 */
getchar( );
getbe( ); /* 滤除空格 */
switch (character)
{ case 'a':

case 'z':
while (letter ( )‖digit ( )) {
concatenation ( ); /* 将当前读入
的字
符送入 token 数组 */
getchar ( );
21/10/29
} 11
retract ( ); /* 扫描指针回退一个字符 */
c=reserve ( );
if (c==0) {
buildlist ( ); /* 将标识符登录到符号表 */
return (id, id 在符号表中的入口指针 );
}
else return ( 保留字码 , null) ;
break;

21/10/29 12
case '0':
case '1':

case '9':
while (digit ( )) {
concatenation ( );
getchar ( );
}
retract ( );
buildlist ( ); /* 将常数登录到常数表中 */
return (num, num 的常数表入口指针 );
break;
21/10/29 13
case '+': return ('+' , null); break;
case‘-': return (‘-' , null); break;
case '*': return ('*' , null); break;
case '<':
getchar ( );
if (character== '=')
return(relop,LE);
else { retract ( );
return (relop,LT);
}
break;
21/10/29 14
case '=':
getchar ( );
if (character=='=') return(relop,EQ);
else { retract ( );
return ('=', _ );
}
break;
case ';': return (';', -); break;
default: error ( );
}

21/10/29 15
 注意:编程实现过程中,
 (1)return(…) :该程序作为语法分析的子
程序,返回相关信息给语法分析程序;若
单独作为一个主程序, return 当作 print 相
关信息。
 (2)getbe() :可增加功能:跳过注释、制
表符和换行符等,碰到换行符则 LineNo
( 记录行号的变量 ) 增加 1 。
 (3)error() :利用 LineNo ,可告诉用户错
误所在的行号,并适当提供纠错信息。
 (4) 增加功能:识别含“ _” 的标识符、无
符号小数、无符号数、符号数 ( 负号 ) 。
21/10/29 16
 (5) 若作为一个主程序,须加一层 while 循环控制:
 while (1= =1)
 { token= ' '; /* 对 token 数组初始化 */
 getchar( );
 getbe( ); /* 滤除空格… */
 if (character!=EOF)
 { switch (character)
 …
 }
 else break; /* end of if */
 } /*end of while */
21/10/29 17
 (6) 考虑不使用 retract() 、不回退字符,每次情况处
理后多读一个字符留下次直接进行判断处理。
 getchar( );
 while (1= =1)
 { token= ' '; /* 对 token 数组初始化 */
 /* 删去 getchar( ); */
 getbe( ); /* 滤除空格… */
 if (character!=EOF)
 { switch (character)
 … /* 去掉每条 retract() 语句;没有
 retract() 的 case 情况加一个 getchar() ; */
 }
 else break; /* end of if */
 } /*end of while */
21/10/29 18

You might also like