附录B 编译程序实验
一、题目
使用直接分析法编制C语言子集的词法分析程序
二、目的
通过设计、编制、调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法.
三、要求
1. 根据具体情况,由同学们自己选取C 语言的一个适当大小的子集(可取一类典型单词,也可以尽可能使各种类型的单词都兼顾到);在实习前一定要制出相应的表.
2. 实验时间:4-8学时.
3. 检查内容及时间:A) 完整的实验报告(算法流程必须要有);
B) 在机器上调试成功的源程序;
实 验 报 告
题目: 用直接分析方法编制PASCAL语言子集的词法分析程序.
一、分析
对于单词符号我们将其分成四类:保留字K、标识符I、常数C和界符P,每类单词符号均可使用一张表格表示.在词法分析过程中,保留字K和界符P这两个表格的内容是固定不变的(由语言确定),源程序字符串只能从其中选取,而标识符I、常数C这两表是在分析过程中不断形成的.
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是K、I、C或P中之一,那么就以单词的二元式形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串.
各类单词的二元式表述均具有相同的结构与长度,形式如下:
(单词种别t,单词自身的值i)
t是单词种别,而单词种别共分为K、I、C、P四类且每类对应一张表格.因此,t实际上就是一个指向这四类中某一类对应表格的指针.i则为指向该类表格中一个特定项目的指针.
所以整个的词法分析过程就是从源程序中获得一个个的单词符号,将这些符号分别填入四张类表中,并且有一个二元式序列构成一个索引,这个索引为以后的语法分析提供处理上的方便.
为了减少实习量,可以适量地选取K,P中的一个子集来进行.如下表:
表1 保留字K表
内部地址
1
2
3
4
5
6
7
8
9
10
保 留 字
BEGIN
CONST
DO
ELSE
END
IF
PROCEDURE
THEN
VAR
WHILE
表2 界符P表
内部地址
1
2
3
4
5
6
7
8
9
10
界 符
;
+
:
:
(
,
)
<
<
<
组合界符
=
=
>
保留字表包括10个有代表性的保留字,界符表包括关系运算符三种(8,9,10),算术运算符(2),分隔符三种(1,4,6),一对圆括号,加上赋值号共10种.这两表的内容表明PASCAL语言的条件语句,赋值语句,WHILE型循环语句,复合语句,过程及变量说明均可作为源程序例子输入给词法分析程序,标识符表I中的每一项包含一个标识符,常数表C中的每一项包含一个整常数,后两表的内容都是在词法分析过程中产生的.
如何从源程序中识别出一个个的单词符号呢?图1中的流图清晰地反映出这一过程.
图1中,双圆圈的状态表示终态,即能到达终态就代表识别出一个单词符号,而带有*号的终态是指处理时应回退一字符.
其它
界符
数字
字母
出错处理
有
C表有此单词否?
形成一项
无
形成(C,i)
十进制数转化成二进制数
K表有此单词否?
形成(I,i)
形成(K,i)
有
无
查界符表
形成(P,i)
源程序完否?
输出二元式
开始
开始
对源程序扫描
扫描到的单词符号
首字母是什么?
完
未完
图2词法分析算法流图
2
字母
非字母与数字
1
字母与数字
0
空白
4
数字
非数字
3
数字
+
6
;
5
8
:
非=
7
=
9
(
10
,
11
)
12
其它
17
14
<
非=
13
15
>
16
=
图1 扫描程序的状态转换图
二、算法
词法分析器在扫描过程中,依次从源程序中取出源字符,根据图1的扫描过程状态转换图,当碰到终态时,即双圆圈的状态时就得到一个单词符号,此时可以根据第一个字符判断单词属于K,I,C,P中哪一类,从而确定单词的"单词种别"和"单词自身的值".整个词法分析的算法流程如图2.
三、实现
选择实习环境为TURBO C2.0语言. 实现程序见附录.
四、总结
上机前应做好准备.即根据实习目的、要求和分析,选择相应的数据结构,使用C语言参照算法中的流程编写词法分析的程序.将编好的程序上机进行调试.注意调试的例子应有词法正确的,也应有词法错误的或是超出所选数据结构范围的.
实验完成达到实习目的之后,若尚有余力者,可以对所选子集适当扩大或是增加相应功能如:扩充界符和保留字数目;允许实型常数;进行词法错误检查;最大范围扩充以至PASCAL语言所有字符的集合.
实验完成以后编写出完整的实验报告,反映出最后的实验学习结果.
附录
/* 词法分析器程序 分析对象为PASCAL语言源程序文件
分析程序主文件: wanalyse.c;
保留字文件: token.txt;
分析结果存放文件: result.txt
WORD ANALYSE DEMO FOR TURBO C 2.0
Copyright (c) 2006, 07 Authors: WQJ
All rights reserved.
From the command line, use:C:\>wanalyse OBJECT.PAS
*/
#include "stdio.h"
#include "ctype.h"
#include "string.h"
#define NULL 0
#define TOKENSUM 100
FILE *fin,*fout,*fp;
char ch,wordget[10];
int i;
void makeword(); /*扫描源程序获得一个单词符号*/
void wordproc(); /*对单词符号进行分类处理生成二元式*/
void makeword(fpoint) /*扫描源程序获得一个单词符号*/
FILE *fpoint;
{
……
}
void wordproc() /*对单词符号进行分类处理生成二元式*/
{
……
}
main(argc,argv) /*词法分析主程序*/
int argc;
char *argv[];
{if (argc==1) /*没有被分析文件作为参数1*/
{printf("Please input filenames of OBJECT\n");
exit(0);
}
if ((fin=fopen(argv[1],"r"))==NULL)
{printf("Cannot open infile\n");
exit(0);
}
if ((fout=fopen("result.txt","w"))==NULL)
{printf("Cannot open outfile\n");
exit(0);
}
if ((fp=fopen("token.txt","r"))==NULL)
{printf("Cannot open tokenfile\n");
exit(0);
}
while(!feof(fin))
{makeword(fin); /*扫描源程序获得一个单词符号*/
wordproc(); /*对单词符号进行分类处理生成二元式*/
}
}
分析对象文件OBJECT.PAS
program exe6(input,output);{PASCAL分析对象程序}
const max=1000;
type ar=array[0..max] of integer;
var m,n,i,j,s:integer; d:ar;
begin
readln(n);
for m:=1 to n do
begin
s:=m*m;
j:=0;
while s>0 do
begin
j:=j+1;
d[j]:=s mod 10;
s:=s div 10
end;
i:=1;
while (d[i]=d[j]) and (ij then writeln(m,m*m:10)
%$ end
end.
分析结果文件RESULT.TXT
(25,-) #PROGRAM#
(101,EXE6)
(46,-) #(#
(68,-) #INPUT#
(54,-) #,#
(69,-) #OUTPUT#
(47,-) #)#
(55,-) #;#
( 5,-) #CONST#
(101,MAX)
(40,-) #=#
(100,1000)
(55,-) #;#
(31,-) #TYPE#
(101,AR)
(40,-) #=#
( 2,-) #ARRAY#
(48,-) #[#
(100,0)
(57,-) #..#
(101,MAX)
(49,-) #]#
(21,-) #OF#
(63,-) #INTEGER#
(55,-) #;#
(33,-) #VAR#
(101,M)
(54,-) #,#
(101,N)
(54,-) #,#
(101,I)
(54,-) #,#
(101,J)
(54,-) #,#
(101,S)
(56,-) #:#
(63,-) #INTEGER#
(55,-) #;#
(101,D)
(56,-) #:#
(101,AR)
(55,-) #;#
( 3,-) #BEGIN#
(77,-) #READLN#
(46,-) #(#
(101,N)
(47,-) #)#
(55,-) #;#
(12,-) #FOR#
(101,M)
(52,-) #:=#
(100,1)
(30,-) #TO#
(101,N)
( 7,-) #DO#
( 3,-) #BEGIN#
(101,S)
(52,-) #:=#
(101,M)
(38,-) #*#
(101,M)
(55,-) #;#
(101,J)
(52,-) #:=#
(100,0)
(55,-) #;#
(34,-) #WHILE#
(101,S)
(43,-) #>#
(100,0)
( 7,-) #DO#
( 3,-) #BEGIN#
(101,J)
(52,-) #:=#
(101,J)
(36,-) #+#
(100,1)
(55,-) #;#
(101,D)
(48,-) #[#
(101,J)
(49,-) #]#
(52,-) #:=#
(101,S)
(18,-) #MOD#
(100,10)
(55,-) #;#
(101,S)
(52,-) #:=#
(101,S)
( 6,-) #DIV#
(100,10)
(10,-) #END#
(55,-) #;#
(101,I)
(52,-) #:=#
(100,1)
(55,-) #;#
(34,-) #WHILE#
(46,-) #(#
(101,D)
(48,-) #[#
(101,I)
(49,-) #]#
(40,-) #=#
(101,D)
(48,-) #[#
(101,J)
(49,-) #]#
(47,-) #)#
( 1,-) #AND#
(46,-) #(#
(101,I)
(42,-) ##
(101,J)
(29,-) #THEN#
(82,-) #WRITELN#
(46,-) #(#
(101,M)
(54,-) #,#
(101,M)
(38,-) #*#
(101,M)
(56,-) #:#
(100,10)
(47,-) #)#
(ERROR,%)
(ERROR,$)
(10,-) #END#
(10,-) #END#
(53,-) #.#
保留字文件TOKEN.TXT
AND
ARRAY
BEGIN
CASE
CONST
DIV
DO
DOWNTO
ELSE
END
FILE
FOR
FUNCTION
GOTO
IF
IN
LABEL
MOD
NIL
NOT
OF
OR
PICKED
PROCEDURE
PROGRAM
RECORD
REPEAT
SET
THEN
TO
TYPE
UNTIL
VAR
WHILE
WITH
+
-
*
/
=
<>
<
>
<=
>=
(
)
[
]
{
}
:=
.
,
;
:
..
'
^
FALSE
TRUE
MAXINT
INTEGER
REAL
BOOLEAN
CHAR
TEXT
INPUT
OUTPUT
DISPOSE
GET
NEW
PACK
PAGE
PUT
READ
READLN
RESET
REWRITE
UNPACK
WRITE
WRITELN
ABS
ARCTAN
CHR
COS
EOF
EOLN
EXP
LN
ODD
ORD
PRED
ROUND
SIN
SQR
SQRT
SUCC
TRUNC
展开阅读全文