收藏 分销(赏)

C语言的词法分析器.docx

上传人:二*** 文档编号:4540871 上传时间:2024-09-27 格式:DOCX 页数:14 大小:146.74KB 下载积分:5 金币
下载 相关 举报
C语言的词法分析器.docx_第1页
第1页 / 共14页
本文档共14页,全文阅读请下载到手机保存,查看更方便
资源描述
1.实验目的及要求 1、目的通过设计、编制、调试一个具体的词法分析程序,加深对词法分析原理的 理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单 词的词法分析方法。 2、 要求根据具体情况,由同学们自己选取C语言的一个适当大小的子集(可 取一类典型单词,也可以尽可能使各种类型的单词都兼顾到);在实 习前一定要制出相应的表。 • 实验时间:4-8学时 • 检查内容及时间:A)完整的实验报告。 B)在机器上调试成功的源程序。 3、软件、硬件环境• Visual studio 2010 , Windows 7 操作系统 ・ 计算机一台2.实验步骤 •分析 对于单词符号我们将其分成四类:保存字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表 内部地址 ~r 2 3 4 5 6 7 8 9 10 保存字 for while DO ELSE IF STATIC TNT SIZEOF BREAK CONTINUE case ' f': case ' g* : case ' h, : case i : case ' j : case ' k': case '1': case ' m : case 'n : case ' o* : case ' p': case ' q': case ' r : case ' s': case ' t': case ' u : case ' v': case ' w* : case ' x : case ' y': case 'l : case ' A* : case ' B': case ' C': case ' D': case ' E* : case ' F': case ' G': case ' H* : case ' I* : case ' J': case ' K': case ' L* : case ' M': case ' N': case ' O': case ' P* : case ' Q': case ' R': case ' S': case ' T* : case ' U': case ' V': case ' M : case ' X* : case ' Y': case ' Z': while(letter() | |digit()) {concat (); getNcxtChai'(fp); )retract(fp); num=reserve(k); 〃保存字 if(num!=0) returntof ile(3, num, id, con); else( val=symbol(id); returntofile(l, val, id, con); ) bi,eak; case 5 0' : case ' 1' : case ’ 21 : case ' 3’ : case ' 4’ : case ' 5’ : case ' 6' : case ' T : case ' 8’ : case ' 9' : while(digit 0)( concatO ;getNextChar(fp); )retract(fp); val=constant(con);returntofile(2, val, id,con); break; case ': getNextChar(fp);if(character二二'二') returntofile(9, 0, id,con); else { retract(fp); returntofile(8, 0, id, con);) break; case ' >> : getNextChar(fp);if(charactcr==,=') returntofile(l1, 0, id,con); else { retract(fp); returntofile(10,0, id,con); ) break; case getNextChar(fp);if(character=:'二') returntofile(13, 0, id, con); else { retract(fp); returntofile(14, 0, id, con);) break; case ': getNextChar(fp);if(character==* =') returntofile(12, 0, id, con); elseerror (); break; case ' +': returntofile(4, 0, id, con);break; case ': returntofile(5, 0, id, con);break; case ' *': returntofile(6, 0, id,con);break; case ' /': returntofilc(7, 0, id, con);break; case '(': returntofile(15, 0, id, con);break; case ')': returntofile(16, 0, id, con);break; case ',': returntofi le(17, 0, id, con);break; case ': returntofilc(18, 0, id, con);break; case ': returntofile(19, 0, id, con);break; case ' {': returntofile(20, 0, id, con);break; case '}': returntofile(21,0, id, con);break; default: error ();ma i n (int argc, char *argv[]) ( 〃初始化标识符和常数结构体 identifier* id=(identifier*)malloc(sizeof(identifier)); constnumber * con=(constnumber*)malloc(sizeof(conslnumber)); con->len=0; id->len=0; argc=3; argv[1 ] ="E:\\filel. txt*;//待分析的文件 argv[2]=,,E:\\fi le2. txt〃;〃保存分析结果的文件 〃从翻开目标文件流 if((fp=fopen(argv[l]»)==NULL) (printf(〃cat: can't open %s\n", *argv); return 1; ) 〃翻开要写二元式的文件流 i f ((fw=fopen (argv [2], "w")) =NULL) (printf ("cat:can't open %s\n/,, argv[2]); return 1; ) while(!feof(fp))( LexAnalyze(k, CODE, id, con, fp, fw); 〃执行词法分析 ) 〃关闭流 fclose(fp); fclose(fw); return 0;} 4.实验结果要分析的C语言程序(1) int i=0, sum=0; while(i<10) (sum=sum+i; i=i+l;结果为: ⑶-)#int#(1. i) (14, -) #=# (2,0)(17, -) #,# (1, sum)(14, -) #=# (2,0) (19,-) #;#⑶-)#wh i I e# (15,-) #(# (1, i) (8,-) #<# (2,10) (16, -) #)# (20, -) #{# (1, sum)(14, -) #=# (1, sum)(4, -) #+# (1, i)(19,-) #;# (1. i)(14, -) #=# (1, i)(4, -) #+# (2.1)(19,-) #;# (21.-) #}#要分析的源程序(2) char s[3]; int i=num/10; while(i>0)char c=i+'()'; strcat(s,&c); ) return s;结果为: (1 ,char) (l,s) (ERROR,[) (2,3) (ERROR,]) (19,-) #;# (3,-) #int# (l,i) (14,-) #=# (l,num) (7,-) #/# (2,10) (19,-) #;# (3,-) #while# (15,-) #(# d,i) (10,-) #># (2,0) (16,-) #)# (20,-) #{# (1 ,char) (l,c) (14,-) #=# (l,i) (4,-) #+# (ERROR;) (2,0) (ERROR;) (19,-) #;# (1,strcat) (15,-) #(# (l,s) (17,-) #,# (ERROR,&) (he) (16,-) #)# (19,-) #;# (21,-) #}# (1,return) (l,s)(19,-) #;# 5.实睑总结分析 上机前应做好准备.即根据实习目的、要求和分析,选择相应的数据结构,使用c语言 参照算法中的流程编写词法分析的程序.将编好的程序上机进行调试.注意调试的例子应有 词法正确的,也应有词法错误的或是超出所选数据结构范围的. 现在我谈一下关于做这个词法分析程序的心得。这个词法分析程序是全部用c语言的语 法写的,幸亏我以前学过C语言。我认为C语言是很好的语言。这次写这个程序算是对我所 学的C语言的一次的检验。在写程序的过程中,也遇到了一些问题,最主要的是文件的输入 与输出,最头疼的是指针。几乎所在的错误都与指针有关。在遇到问题以后,我们不要良惧, 我们可以通过程序调试,找出问题的所在,只要找到问题的源,就总在解决它的方法。 在这个分析程序中,我加了注释,是很容易看懂的,而且程序的功能模块也分得很清 楚。在写大型的程序时,这两点我认为是非常重要的。 附录资料:不需要的可以自行删除Abstract: Based on the comprehensive analysis on the plastic part's structure service requirement, mounding quality and mould menu factoring cost. A corresponding injection mould of internal side core pulling was designed. By adopting the multi-direction and multi-combination core-pulling. A corresponding injection mould of internal side core pulling was designed, the working process of the mould was introduced C语言详解一枚举类型注:以下全部代码的执行环境为VC++6.0 在程序中,可能需要为某些整数定义一个别名,我们可以利用预处理指令#define来完成这 项工作,您的代码可能是: #define MON Idcfine TUE 2 # define WED 3define THU 4 # dcfine FRI 5define SAT 6 # define SUN 7在此,我们定义一种新的数据类型,希望它能完成同样的工作。这种新的数据类型叫枚举型. 1 .定义一种新的数据类型-枚举型 以下代码定义了这种新的数据类型-枚举型enum DAY ( MON=1,TUE, WED, THU, FRI, SAT, SUN}; (1)枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号, 隔开。 (2) DAY是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。 (3)第•个枚举成员的默认值为整型的0,后续枚举成员的值在前•个成员上加1。 (4)可以人为设定枚举成员的值,从而自定义某个范围内的整数. (5)枚举型是预处理指令#define的替代。 (6)类型定义以分号;结束。 2 .使用枚举类型对变量进行声明新的数据类型定义完成后,它就可以使用了。我们已经见过最基本的数据类型,如:整型int, 单精度浮点型float,双精度浮点型double,字符型char,短整型short等等。用这些基本数据 类型声明变量通常是这样: char a; 〃变量a的类型均为字符型char charletter;intx, y, z; 〃变量x,y和z的类型均为整型int int number;double m, n; double result; 〃变量result的类型为双精度浮点型double 既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。 方法一:枚举类型的定义和变量的声明分开enum DAY { MON= I, TUE, WED, THU, FRI, SAT, SUN ); enum DAY yesterday;enum DAY today; enum DAY tomorrow; 〃变显 tomorrow 的类型为枚举型 enurn DAYenum DAY good_day. bad_day; 〃变量 good_day 和 bad_day 的类型均为枚举型 enum DAY 方法二:类型定义与变量声明同时进行: enum 〃跟第一个定义不同的是,此处的标号DAY省略,这是允许的。 {Saturday, sunday = 0, monday, (uesday, Wednesday, thursday, friday } workday;//变量workday的类型为枚举型enum DAYenum week { Mon= 1, Tue, Wed. Thu, Fri Sat, Sun} days; 〃变量 days 的类型为枚举型 enum week enum BOOLEAN { false, true } end_flag, malch_flag; 〃定义枚举类型并声明了两个枚举型变 量方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明: typedef enum workday Saturday, sunday = 0,monday, tuesday, Wednesday, thursday, friday } workday;//此处的workday为枚举型enum workday的别名workday today, tomorrow; 〃变量 today 和 tomorrow 的类型为枚举型 workday,也即 cnum workday enum workday 中的 workday 可以省略: typedef enum {Saturday, sunday = 0, monday, tuesday, Wednesday, (hursday, friday } workday;//此处的workday为枚举型enum workday的别名workday today, tomorrow; 〃变量 today 和 tomorrow 的类型为枚举型 workday,也即 enum workday 也可以用这种方式: typedef enum workday { Saturday, sunday = 0, monday, tuesday, Wednesday, thursday, friday );workday today, tomorrow; 〃变量 today 和 tomorrow 的类型为枚举型 workday,也即 enum workday 注意:同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常 量。错误例如如下所示: 错误声明一:存在同名的枚举类型typedef enum { Wednesday, thursday, friday} workday; typedef enum WEEK | Saturday, sunday = 0, monday, } workday;错误声明二:存在同名的枚举成员 lypedef enum { Wednesday, (hursday, friday} workday」; typcdcf cnum WEEK { Wednesday, sunday = 0, monday,} workday_2; 3 .使用枚举类型的变量对枚举型的变量赋值。 实例将枚举类型的赋值与基本数据类型的赋值进行了比照: 方法一:先声明变量,再对变量赋值#include<stdio.h> /*定义枚举类型*/enum DAY { MON=1,TUE, WED, THU, FRI, SAT, SUN }; void main()( /*使用基本数据类型声明变量,然后对变量赋值*/ int x, y, z; x= 10; y = 20; z = 30: /*使用枚举类型声明变量,再对枚举型变量赋值*/ enum DAY yesterday, today, tomorrow; yesterday = MON; today = TUE; tomorrow = WED; printf("%d %d %d \n", yesterday, today, tomorrow);方法二:声明变量的同时赋初值 #include <stdio.h>/*定义枚举类型*/ enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN }; 界符 + — * / < <= > >= 1 = —— = ( ) * • * 9 ( ) 表3单词 符号的编码 单词符号 类别编码 标识符 1 常数 2 保存字 3 + 4 — 5 * 6 / 7 < 8 <= 9 > 10 >= 11 1 = 12 == 13 = 14 ( 15 ) 16 9 17 : 18 * 19 { 20 } 21 保存字表包括10个有代表性的保存字,界符表包括关系运算符,算术运算符,分隔符 三种,一对圆括号,加上赋值号,花括号,分号,引号.这两表的内容说明C语言的条 件语句,赋值语句,WHILE型循环语句,复合语句,过程及变量说明均可作为源程序例 子输入给词法分析程序,标识符表I中的每一项包含一个标识符,常数表C中的每一项 包含一个整常数,后两表的内容都是在词法分析过程中产生的. 如何从源程序中识别出一个个的单词符号呢?图1中的流图清晰地反映出这一过 程. 图1中,双圆圈的状态表示终态,即能到达终态就代表识别出•个单词符号,而带有火 号的终态是指处理时应回退一字符. •算法词法分析器在扫描过程中,依次从源程序中取出源字符,根据图1的扫描过程状态转换图, 当碰到终态时,即双圆圈的状态时就得到一个单词符号,此时可以根据第一个字符判断单词 属于K, I, C, P中哪一个类,从而确定单词的“单词种别”和“单词自身的值”。 void main。 {/*使用基本数据类型声明变量同时对变量赋初值*/ int x=10, y=20, z=30; /*使用枚举类型声明变量同时对枚举型变量赋初值*/ enum DAY yesterday = MON, today = TUE, tomorrow = WED; printf("%d %d %d \n", yesterday, today, tomorrow);} 方法三:定义类型的同时声明变量,然后对变量赋值。 #include <stdio.h>/*定义枚举类型,同时声明该类型的三个变量,它们都为全局变量*/ enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today, tomorrow;/*定义三个具有基本数据类型的变量,它们都为全局变量号 int x, y, z;void main() { /*对基本数据类型的变量赋值*/ x= 10; y = 20; z = 30; /*对枚举型的变量赋值*/ yesterday = MON; today = TUE; tomorrow = WED; printf("%d %d %d \n", x, y, z); 〃输出:10 20 30 prinlf("%d %d %d \n", yesterday, today, tomorrow); 〃输出:12 3) 方法四:类型定义,变量声明,赋初值同时进行。 #include <stdio.h>/*定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量*/ enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN) yesterday = MON, today = TUE, tomorrow = WED;/*定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量*/ int x = 10, y = 2O,z = 3O;void main() printf("%d %d %d \n", x, y, z); 〃输出:10 20 30 prinlf("%d %d %d \n", yesterday, today, tomorrow); 〃输出:12 3) 3.1 对枚举型的变量赋整数值时,需要进行类型转换。 #includc <stdio.h>enum DAY { MON=1,TUE, WED, THU, FRI, SAT, SUN ); void main(){ enum DAY yesterday, today, tomorrow; yesterday = TUE; today = (enum DAY) (yesterday + 1); 〃类型转换 tomorrow = (enum DAY) 30; 〃类型转换 //tomorrow = 3; 〃错误 printf("%d %d %d \n”, yesterday, today, tomoiTow); 〃输{i| : 2 3 30 )使用枚举型变量 #include<stdio.h>enum { BELL= '\a', BACKSPACE = U', HTAB='\t; RETURN= V, NEWLINE = '\n; 3.2 B='\v; SPACE='' cnum BOOLEAN { FALSE = 0, TRUE } match_flag;void main() | int index = 0; int count_oLle(ter = 0; int count_oCspacc = 0; char str(l = 'Tm Ely efod";match_flag = FALSE; for(; str [index] != '\0'; indcx++) if( SPACE != str[index]) count_oMet(er++;else match_nag = (enum BOOLEAN) 1; count_oiLspace++;printf("%s %d times %c", match_flag ? "match" : "not match", count_of_space, NEWLINE); prinlf("count of letters: %d %c%c", count_of_letter. NEWLINE, RETURN); 输出: match 2 timescount of letters: 10 Press any key (o continue.枚举类型与sizeof运算符 #include <stdio.h> cnum escapes (BELL= W, BACKSPACE = '\b;HTAB= '\t', RETURN =V, NEWLINE = '\n', VTAB= '\v',SPACE=" );enum BOOLEAN { FALSE = 0, TRUE } match_llag; void main(){ printf("%d bytes \n", sizeof(enum escapes)); //4 bytes printf("%d bytes \n", sizeof(escapes)); //4 bytesprintf("%d bytes \n", sizcof(cnuni BOOLEAN)); //4 bytes printf("%d bytes \n", sizeof(BOOLEAN)); //4 bytes printf("%d bytes \n", sizeof(match_flag)); //4 bytes printf("%d bytes \n", sizeof(SPACE)); //4 bytesprintf("%d bytes \n'\ sizeof(NEWLINE)); //4 bytes printf("%d bytes \n,\ sizcof(FALSE)); //4 bytes printf("%d bytes \n", sizeof(0)); //4 bytes) 4 .综合举例 #includc<stdio.h>enum Season ( spring, summer=100, fall=96. winter );typedef enum Monday, I'ucsday. Wednesday, Thursday, Friday, Saturday, Sunday }Weekday; void main() /* Season */ printf("%d \nH, spring); // 0 printf("%d, %c \n'\ summer, summer); // 100, d printf("%d \n'\ fall+wintcr); // 193 Season mySeason=winter; if(winter==mySeason)printf("mySeason is winter \n"); // mySeason is winter int x=100; if(x=summer)printf("x is equal to summer\n"); // x is equal to summer printf("%d bytes\n", sizeof(spring)); // 4 bytes /* Weekday */ printf("sizeof Weekday is: %d \n", sizeof(Weekday)); //sizeof Weekday is: 4 Weekday today = Saturday; Weekday tomorrow: if(today == Monday)tomorrow = Tuesday; elsetomorrow = (Weekday) (today + 1); //remember to convert from int to Weekday 本文来自CSDN--xiaobai32966博客 空白字母与数字 图1扫描程序的状态转换图说明:这个图只是大概表达一个词法分析的思路,由于不知道加入,所以并不完全准确。 2.实验内容 流程图、程序 图2词法分析算法流图 源程序#include <stdio. h> # include <string. h>#include <ctype. h> #include <stdlib.h>#include <assert. h> #define LENGTH 1 10 〃定义保存字的大小 FILE * fp=NULL; 〃输出流指针FILE * fw=NULL; 〃输入流指针 char character; 〃字符char tokcn[16]; 〃字符数组,用来存放已读入的字符序列 〃编码表char* CODE[] = {*identifier*/* 标识符 */, "constant"/* 常数 */, "keyword"/* 保存字 〃保存字表 char*kLJ=l for , while , do , else , if , static , int , sizeof , break , continue }; 〃标识符结构体 typedef struct ( char * I [256];〃标识符数组 int len;〃标识符数量 } identifier;〃常量结构体 typedef struct { int cont[300];〃存放常量的数组 int len;〃常量的数目 } constnumber;〃读入一个字符,从输入流中读入一个字符到变量character中。 void getNextChar(FILE *ifp) (if((character=getc(ifp))==EOF) exit (1); )〃读入非空白字符,检查变量character中的字符是否为空白字符或|口|车或换行符。假设是, 〃那么调用getNextChar()读入下一个字符,直到character中的字符满足条件. void getnbc(FILE *ifp) ( whi le(character=, | | character==, \n \ character==9) (getNextChar(ifp); )} 〃连接字符串,把character中的字符连接到token数组的结尾。 void concat() char * ct=&character; strcat(token, ct);〃判断是否为字母。 int letter() return isalpha(character);) 〃判断是否为数字int digit() ( return isdigit(character);) 〃回退字符,将刚读入的character中的字符回退到输入流中。并把character中的值置为 空。 void retract(FILE *ifp)( (ifp->_cnt)++; (ifp->_ptr)—; character=,';) 〃处理保存字,对存放在token中的字符串查保存字,假设查到,那么返回该保存字的类别编码, 否那么返回0. int reserve(char **k)( int i; for(i=0;i<LENGTHl;i++)if (strcmp(token, k[i])=0) return i+1; return 0;} 〃处理标识符,对存放在token中的字符串查找符号表,假设查到,那么返回它在符号表的位置, 〃存入常数表中,并返回它在常数表中的位置编号。 int symbol(identifier * id)( int i; for(i=0;i<id->lcn;i++)if (strcmp(token, id->I[i])=0) return i+1; if(id->len>256)assert(0); id->I[id->len]=token; id->len++; return id->len;} 〃将数字字符串转化为整数。 int strtonumber() int i; int sum=O; for(i=0;i<strlen (token);i++) (sum=10*sum+(token[i], 01); ) return sum;) 〃常数存入常数表的函数,将token中的数字串(实际上是字符串),转化成标准的二进制 值(整数值)〃存入常数表中,并返回它在常数表中的位置编号。 int constant(constnumber * con)( con->cont[con->len]=strtonumber(); con->len++; return con->len;) 〃将整数值转化为字符串char * numbertoString(int num) ( char s[3]; int i=num/10; while(i>0) (char c=i+' O'; strcat(s,&c); ) return s;) 〃将结果写入到文件并且输出到屏幕。 void returntofile(int num, int val, identifier *id, constnumber *con)( int i; int _num=num; char c; c='('; putc(c, fw); printfc); i= num/10; while (i>0) ( _num=_num-10*i;c=(i+'O'); printf("Sc",c);putc(c, fw); i=_num/10; } c=_num+, 0'; printfc); putc(c, fw); printf; putcC ,', fw); 〃如果是标识符或常数那么放入括号内。 if(num==l) //处理标识符 (printf id->I[val-l]); printf (")");prinlf("\n"); fputs(id->I[val-l], fw);putc(*)', fw); putc(' \n , fw); ) if(num-2) //处理常数 (_num=con->cont[val-1]; i=_num/10; while(i>0) (_num=_num-10*i; c=(i+'O');printf (飞c”, c); putc(c, fw);i=_num/10; }c=. num+, 0'; printf("Sc",c);printf (〃)”); printf (*\n*);putc(c, fw); putc
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 通信科技 > 开发语言

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服