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

合集下载

编译原理(2)词法_2(NFA、DFA的确定化和化简)

编译原理(2)词法_2(NFA、DFA的确定化和化简)
西北农林科技大学本科教程
第 3 讲
主讲教师:赵建邦
本讲目标

第二章《词法分析》2.3-2.5节

2.3 2.4 2.5
正规表达式与有限自动机简介 正规表达式到优先自动机的构造 词法分析器的自动生成

重点掌握

有限自动机理论 有限自动机的构造、确定化和化简
第二章 词法分析
2.1 2.2
• DFA是一个五元组,Md= (S, ∑, f, s0 , Z) ,其中: (1) S是一个有限状态集合,它的每个元素称为一个状态 (2) ∑是一个有穷字母表,它的每个元素称为一个输入字符 (3) f是一个从S×∑至S的单值映射,也叫状态转移函数 (4) s0∈S 是唯一的初态 (5) Z S 是一个终态集
J中的每一个状态经过任意条 ε通路得到ε_CLOSURE(J) =
4
Ia= {5,6,2,3,8,4,7}
2.4

正规表达式到有限自动机的构造
2.4.2:NFA的确定化(子集法)
(1) 构造一张转换表,第一列记为状态子集I,对于不同的符号
(a∈Σ),在表中单设一列Ia ; (2) 表的首行首列置为ε_CLOSURE(s0),其中s0为初始状态; (3) 根据首行首列的I,为每个a求其Ia 并记入对应的Ia 列中, 如果此Ia 不同于第一列中已存在的所有状态子集I,则将其
si
r1 r2 r1 *
sj sj
si
si
sj
si
2.4
正规表达式到有限自动机的构造
例2.6 对给定正规表达式 b*(d|ad)(b|ab)+ 构造其NFA M [解答] 先用R+=RR*改造正规表达式 b*(d|ad)(b|ab)+ = b*(d|ad)(b|ab)(b|ab)* 按照正规式从左到右构造NFA: b X ε 1 ε 2 a 3

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

2.2  一个简单的词法分析器示例
2014-9-26 9
(4)concatenation( ): 将token中字符串与 character中字符连接作为token中的新 字符串。 (5)letter( )和digit( ): 判断character中的字 符是否为字母和数字的布尔函数,若是 则返回true, 否则返回false。 (6)reserve( ): 按token数组中的字符串查 保留字表, 若是保留字则返回其编码, 否则返回0。
2014-9-26 5

对保留字专设对应的状态转换图:

C语言子集对应的状态转换图如下:
6
2014-9-26
空白 字母或数字
开始 0
字母 1 非字母数字 2 * 返回(id, id在符号表中位置)
数字 数字 3 4 * 非数字 + 5 - 6 * < = ; 其它
2014-9-26
或返回(保留字, -)
2014-9-26 8
2.2.3 状态转换图的实现 状态转换图易于用程序实现,最简单的 办法是让每个状态对应一小段程序。对于 图2–5,首先引进一组变量和过程: (1)character: 字符变量,存放最新读入 的源程序字符。 (2)token: 字符数组,存放构成单词符号 的字符串。 (3)getbe( ): 若character中字符为空,则 调用getchar( ),直至character为非空。
2014-9-26 15
case '=': getchar ( ); if (character=='=') return(relop,EQ); else { retract ( ); return ('=', _ ); } break; case ';': return (';', -); break; default: error ( ); }

第2章 词法分析-sxw

第2章  词法分析-sxw
2.3.1 正规表达式与正规集
正规表达式是典型的词法规则描述工具.
正规式也称正则表达式. 正规表达式(regular expression)是说明单词的模 式(pattern)的一种重要的表示法(记号),是定义正 规集的数学工具.我们用以描述单词符号.下面是 正规式和它所表示的正规集的递归定义.
第2章 词法分析
程序语言中使用的标识符是一个以字母开头的字 母数字串,如果字母用letter表示,数字用digit表示, 则标识符可表示为 letter (letter∣digit)* 其中,letter与 (letter∣digit)*的并置表示两者的连 接;括号中的"∣"表示letter或digit两者选一;"*" 表示零次或多次引用由"*"标记的表达式; (letter∣digit)*是letter∣digit的零次或多次并置,即表 示 一 长 度 为 0 , 1 , 2 , … 的 字 母 数 字 串 ; letter (letter∣digit)*表示以字母开头的字母数字串,也即标 识符集.letter (letter∣digit)*就是表示标识符的正规式, 而标识符集就是这个正规式所表示的正规集.
第2章 词法分析
retract ( ); c=reserve ( ); if (c==0) { buildlist ( );
/*扫描指针回退一个字符*/
/*将标识符登录到符号表中*/
return (id,指向id的符号表入口指针); } else return (保留字码,null); break;
第2章 词法分析
x i y
j
k
图2–2 不同输入字符的状态转换
第2章 词法分析

简单的词法分析器

简单的词法分析器

简单词法分析器运行截图:源码如下:(时间有限,仅供参考)/****************************************************** *Name :SimpleParser.c*Copyright :free*Function :简单的词法分析器*Create date:2014.5*Author :geekswg@*Description:可以识别{},数字,字母,+-/*,><=;******************************************************/ #include<stdio.h>//#include<stdbool.h>//C99包含bool头文件,VC6.0报错#include<memory.h>#include<string.h>//包含strcmp()函数//宏定义bool类型兼容VC6.0#define bool char#define true 1#define false 0#define MAXSIZE 500#define SOC '{' //start of comment#define EOC '}' //end of comment/*#define ADD +#define MIN -#define MUL *#define DIV /*/char inStr[MAXSIZE];//bool型,是否是关键字,是返回truebool isKeyword(char s1[],char s2[]){if(!strcmp(s1,s2))return true;elsereturn false;}//bool型,是否是数字,是返回truebool isDigit(char c){if(c > 47 && c<58){//ASCII(0-9)return true;}elsereturn false;}//bool型,是否是字符,是返回truebool isLetter(char c){if((c > 64 && c < 91) || (c >96 && c <123)){//A-Z,a-z)return true;}elsereturn false;}//读入待分析的字符串;void inFile(char inStr[]){FILE *fp;//文件指针int i = 0;char filename[50]; //文件名memset(filename,0,sizeof(filename)); //清空数组;printf("\nPlease input the file:");scanf("%s",&filename);// printf("\n%s",filename);while((fp = fopen(filename,"r"))==NULL){//以只读方式打开文件printf("\nCan't Find file!Input again:");scanf("%s",&filename);}while(!feof(fp)){//直到文件结束符停止fscanf(fp,"%c",&inStr[i]);//将文件中的数据写到inStr中i++;}inStr[i]='\0';fclose(fp);}//录入待分析的字符串;void inString(char inStr[]){//录入函数int i=0;char inchar;printf("SimpleParser For Test \n");printf("Please Inpuet Strings:(End of '#')\n:");while( inchar !='#'){//以#为结束符标志;scanf("%c",&inchar);inStr[i++] = inchar;}}/**********************************//打印数组//参数待分析字符串,备注信息字符串//***********************************/void display(char inStr[],char info[]){//打印数组int i = 0;printf("\n*************************************\n");while( inStr[i] != '\0' ){//直到数组结束标志printf("%c",inStr[i++]);//打印元素}printf("\t\t%s",info);// printf("\n*************************************\n");// printf("#\n");}/**********************************//parser for comment//参数待分析字符串,位置下标int i// 返回值位置下标int i***********************************/int parser_com(char inStr[],int i){//parser for comment"{}"char temp[MAXSIZE] ;//存放{}内的字符串memset(temp,0,sizeof(temp)); //清空数组,以防止第二次调用时有上次的字符串;int t=0;while(inStr[++i] != EOC){temp[t]=inStr[i];t++;}// printf("Comment \t:");display(temp,"Comment");return i;}/**********************************//parser for letter//参数待分析字符串,位置下标int i// 返回值位置下标int i***********************************/int parser_letter(char inStr[],int i){int t = 0;char temp[MAXSIZE];memset(temp,0,sizeof(temp)); //清空数组;while(isDigit(inStr[i]) || isLetter(inStr[i])){//如果是数字或字母temp[t++] = inStr[i];i++;}//判断是否是关键字,如需添加关键字添加else if即可//若使用关键字表应该效果更好if(isKeyword(temp,"int")){display(temp,"ID_KeyWords");}else if(isKeyword(temp,"char")){display(temp,"ID_KeyWords");}// printf("Letter \t:");else{display(temp,"inID");}return --i;}int parser_digit(char inStr[],int i){int t = 0;char temp[MAXSIZE];memset(temp,0,sizeof(temp)); //清空数组;while(inStr[i] != ' ' && inStr[i] != '\n' && isDigit(inStr[i])){ temp[t++] = inStr[i];i++;}// printf("Digit \t:");display(temp,"inNum");return --i;}/*// prasers for operators like "+,-,* /"//之后放入了parser()中了int parser_ops(char inStr[],int i){int t = 0;char temp[MAXSIZE];memset(temp,0,sizeof(temp)); 清空数组;return i;}*/// prasers for relationship operators like ">,<,="int parser_rel(char inStr[],int i){int t = 0;char temp[MAXSIZE];memset(temp,0,sizeof(temp)); //清空数组;while(inStr[i]=='>' || inStr[i]=='<' || inStr[i]=='='){temp[t] = inStr[i];t++;i++;}// printf("\nRelationship_Operator\t:");display(temp,"Relationship_Operators");return --i;}/**********************************//词法分析主程序,//参数待分析字符串//***********************************/void parser(char inStr[]){int i = 0;while(inStr[i] != '#'){/*switch(inStr[i]){case '{': i = pareser_com(inStr,i);break;//如果是{,使用case ' ': ;break; //如果是空格跳过case '+':;break;default:;break; //}*///之前使用switch,后来觉得if ,else更方便if(inStr[i] == SOC){//SOC'{'-start of commenti = parser_com(inStr,i);//如果是{,使用pareser_com;}else if(inStr[i] == '+'){display("+","Operator");}else if(inStr[i] == '-'){display("-","Operator");}else if(inStr[i] == '*'){display("*","Operator");}else if(inStr[i] == '/'){display("/","Operator");}else if(inStr[i]=='>' || inStr[i]=='=' || inStr[i]=='<'){i = parser_rel(inStr,i);//parser for relationship;}/*else if(inStr[i] > 47 && inStr[i] <58){//0-9;i = parser_digit(inStr,i);}*/else if(isDigit(inStr[i])){i = parser_digit(inStr,i);}/*else if((inStr[i] >64 && inStr[i]<91)|| (inStr[i]>96 && inStr[i] <123)){//A-Z,a-zi = parser_letter(inStr,i);}*/else if(isLetter(inStr[i])){i = parser_letter(inStr,i);}i++;}memset(inStr,0,sizeof(inStr));//清空数组;}//主菜单;void menu(){char choice;printf("\t\tSimpleParser\n");printf("1)inString from file\n2)inString from Inputing\n3)exit\n");printf("Your choice:");scanf("%c",&choice);while(choice!='1'&& choice!='2' && choice!='0' ){printf("\nerror,Your choice:");scanf("%c",&choice);}switch(choice){case '0':{system("PAUSE");exit(0);};break;case '1':inFile(inStr); break;case '2':inString(inStr); break;default:;break;}}int main(){/*inString(inStr);inFile(inStr);*/menu();printf("\nInString :");display(inStr,"\n*************************************");printf("\n\t\tCompile Begin");parser(inStr);system("PAUSE"); //调用系统暂停return 0;}。

(完整版)词法分析器(c语言实现)

(完整版)词法分析器(c语言实现)

词法分析c实现一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。

二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。

(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。

空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。

2.2 各种单词符号对应的种别码:输入:所给文法的源程序字符串。

输出:二元组(syn,token或sum)构成的序列。

其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。

例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的C语言程序源代码:#include <stdio.h>#include <string.h>char prog[80],token[8],ch;int syn,p,m,n,sum;char *rwtab[6]={"begin","if","then","while","do","end"};scaner();main(){p=0;printf("\n please input a string(end with '#'):/n");do{scanf("%c",&ch);prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){case 11:printf("( %-10d%5d )\n",sum,syn);break;case -1:printf("you have input a wrong string\n");getch();exit(0);default: printf("( %-10s%5d )\n",token,syn);break;}}while(syn!=0);getch();}scaner(){ sum=0;for(m=0;m<8;m++)token[m++]=NULL;ch=prog[p++];m=0;while((ch==' ')||(ch=='\n'))ch=prog[p++];if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))){ while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) {token[m++]=ch;ch=prog[p++];}p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){ syn=n+1;break;}}else if((ch>='0')&&(ch<='9')) { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=11;}else switch(ch){ case '<':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=22;token[m++]=ch;}else{ syn=20;p--;}break;case '>':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=24;token[m++]=ch;}else{ syn=23;p--;}break;case '+': token[m++]=ch;ch=prog[p++];if(ch=='+'){ syn=17;token[m++]=ch;}else{ syn=13;p--;}break;ch=prog[p++];if(ch=='-'){ syn=29;token[m++]=ch;}else{ syn=14;p--;}break;case '!':ch=prog[p++];if(ch=='='){ syn=21;token[m++]=ch;}else{ syn=31;p--;}break;case '=':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=25;token[m++]=ch;}else{ syn=18;p--;}break;case '*': syn=15;token[m++]=ch;break;case '/': syn=16;token[m++]=ch;break;case '(': syn=27;token[m++]=ch;break;case ')': syn=28;break;case '{': syn=5;token[m++]=ch;break;case '}': syn=6;token[m++]=ch;break;case ';': syn=26;token[m++]=ch;break;case '\"': syn=30;token[m++]=ch;break;case '#': syn=0;token[m++]=ch;break;case ':':syn=17;token[m++]=ch;break;default: syn=-1;break;}token[m++]='\0';}四、结果分析:输入begin x:=9: if x>9 then x:=2*x+1/3; end # 后经词法分析输出如下序列:(begin 1)(x 10)(:17)(= 18)(9 11)(;26)(if 2)……如图5-1所示:。

第3章 词法分析(3)

第3章 词法分析(3)

3.4 正规式与有穷自动机的等价性
1. NFA M正规式R
在消结过程中,逐步用正规式来标记弧, 规则如下:
1.对于
1
2.对于
R1
2
R2
代之为
3
1
R1 R2
3
代之为 R1 R1| R2 1 2 1 2 R2 R2 3.对于 代之为 R1R2﹡R3 R 1 R 3 1 3 1 2 3
例如:有NFA M如图3.14,求其等价的正规式R。
a,b a 3
x ε 0 b 1 a|b a|b x ε 0
aa
a
4
ε
b
y (a|b)*(aa|bb)(a|b)* x y ε 2 a,b a|b aa(a|b) * y bb(a|b) *
4
ε y x
bb
2
ε
a|b
ε
0
3.4 正规式与有穷自动机的等价性
课堂练习 求以下NFA的正规式 a a 3 a 1 2 b
第一步
a
5 6 b
b
4
b
a
a
3
a
a
s

1 2
b
5 b
4 b

6 b

z
3.4 正规式与有穷自动机的等价性
第二步
a|b s 1 2
aa bb aa|bb 5
a|b
6

z
第三步
s
第四步
(a|b)*
2
5
(a|b)*
z
s
(a|b)*(aa|bb)(a|b)*
z
课堂讲解
• 【例5.12】第72页 • 【例5.13】第73页

实验一、词法分析器(含源代码)

实验一、词法分析器(含源代码)

词法分析器实验报告一、实验目的及要求本次实验通过用C语言设计、编制、调试一个词法分析子程序,识别单词,实现一个C语言词法分析器,经过此过程可以加深对编译器解析单词流的过程的了解。

运行环境:硬件:windows xp软件:visual c++6.0二、实验步骤1.查询资料,了解词法分析器的工作过程与原理。

2.分析题目,整理出基本设计思路。

3.实践编码,将设计思想转换用c语言编码实现,编译运行。

4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。

通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提高分析能力。

三、实验内容本实验中将c语言单词符号分成了四类:关键字key(特别的将main说明为主函数)、普通标示符、常数和界符。

将关键字初始化在一个字符型指针数组*key[]中,将界符分别由程序中的case列出。

在词法分析过程中,关键字表和case列出的界符的内容是固定不变的(由程序中的初始化确定),因此,从源文件字符串中识别出现的关键字,界符只能从其中选取。

标识符、常数是在分析过程中不断形成的。

对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是关键字、普通标示符、常数或界符中之一,那么就将此单词以文字说明的形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。

输出形式例如:void $关键字流程图、程序流程图:程序:#include<string.h>#include<stdio.h>#include<stdlib.h>#include<ctype.h>//定义关键字char*Key[10]={"main","void","int","char","printf","scanf","else","if","return"}; char Word[20],ch; // 存储识别出的单词流int IsAlpha(char c) { //判断是否为字母if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsNum(char c){ //判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}int IsKey(char *Word){ //识别关键字函数int m,i;for(i=0;i<9;i++){if((m=strcmp(Word,Key[i]))==0){if(i==0)return 2;return 1;}}return 0;}void scanner(FILE *fp){ //扫描函数char Word[20]={'\0'};char ch;int i,c;ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符if(IsAlpha(ch)){ //判断该字符是否是字母Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)||IsAlpha(ch)){ //判断该字符是否是字母或数字Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0'; //'\0' 代表字符结束(空格)fseek(fp,-1,1); //回退一个字符c=IsKey(Word); //判断是否是关键字if(c==0) printf("%s\t$普通标识符\n\n",Word);//不是关键字else if(c==2) printf("%s\t$主函数\n\n",Word);else printf("%s\t$关键字\n\n",Word); //输出关键字 }else //开始判断的字符不是字母if(IsNum(ch)){ //判断是否是数字Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)){Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0';fseek(fp,-1,1); //回退printf("%s\t$无符号实数\n\n",Word);}else //开始判断的字符不是字母也不是数字{Word[0]=ch;switch(ch){case'[':case']':case'(':case')':case'{':case'}':case',':case'"':case';':printf("%s\t$界符\n\n",Word); break;case'+':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);//运算符“+=”}else if(ch=='+'){printf("%s\t$运算符\n\n",Word); //判断结果为“++”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“+”}break;case'-':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); }else if(ch=='-'){printf("%s\t$运算符\n\n",Word); //判断结果为“--”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“-”}break;case'*':case'/':case'!':case'=':ch=fgetc(fp);if(ch=='='){printf("%s\t$运算符\n\n",Word);}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'<':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); //判断结果为运算符“<=”}else if(ch=='<'){printf("%s\t$运算符\n\n",Word); //判断结果为“<<”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“<”}break;case'>':ch=fgetc(fp);Word[1]=ch;if(ch=='=') printf("%s\t$运算符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'%':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);}if(IsAlpha(ch)) printf("%s\t$类型标识符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$取余运算符\n\n",Word);}break;default:printf("无法识别字符!\n\n"); break;}}}main(){char in_fn[30]; //文件路径FILE *fp;printf("\n请输入源文件名(包括路径和后缀名):");while(1){gets(in_fn);//scanf("%s",in_fn);if((fp=fopen(in_fn,"r"))!=NULL) break; //读取文件内容,并返回文件指针,该指针指向文件的第一个字符else printf("文件路径错误!请重新输入:");}printf("\n******************* 词法分析结果如下 *******************\n");do{ch=fgetc(fp);if(ch=='#') break; //文件以#结尾,作为扫描结束条件else if(ch==' '||ch=='\t'||ch=='\n'){} //忽略空格,空白,和换行else{fseek(fp,-1,1); //回退一个字节开始识别单词流scanner(fp);}}while(ch!='#');return(0);}4.实验结果解析源文件:void main(){int a=3;a+=b;printf("%d",a);return;}#解析结果:5.实验总结分析通过本次实验,让再次浏览了有关c语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。

第二章 词法分析

第二章 词法分析

8
单词种别表示单词的种类, (1) 单词种别表示单词的种类,是语法分 析所需要的信息。 析所需要的信息。 一个语言的单词符号如何划分种类、 一个语言的单词符号如何划分种类、分为 几类、如何编码都属于技术性问题, 几类、如何编码都属于技术性问题,主要取 决于处理上的方便。 决于处理上的方便。 通常让每种单词对应一个整数码, 通常让每种单词对应一个整数码,这样可 最大限度地把各个单词区别开来。 最大限度地把各个单词区别开来。
6
(4) 运 算 符 : 如 “ +” 、 “ − ” 、 “ * ” 、 /”、 >”、 <”等 “/”、“>”、“<”等。 (5) 界符:在语言中是作为语法上的分界符 界符: 号使用的, 号使用的 , 如“ , ”、 “ ;” 、 “( ” 、 “ ) ” 等。 一个程序语言的保留字、 一个程序语言的保留字、运算符和界符 的个数是确定的, 的个数是确定的,而标识符或常数的使用则 不限定个数。 不限定个数。
24
终态一般对应一个return( 语句。 终态一般对应一个return( )语句。 return意味着从词法分析器返回到调用段 return意味着从词法分析器返回到调用段 一般指返回到语法分析器。 ,一般指返回到语法分析器。
图2–4 含有分支或回路的状态示意 (a) 含分支的状态 ;(b) 含回路的状态 含分支的状态i; 含回路的状态i
(3,’if’) (1,指向 的符号表入口) 指向i (1,指向i的符号表入口) (4,’=’) (2,’5’) (3,’then’) (1,指向 的符号表入口) 指向x (1,指向x的符号表入口) (4,’:=’) (1,指向 的符号表入口) 指向y (1,指向y的符号表入口) (5,’;’)

编译原理第三章练习题答案

编译原理第三章练习题答案

编译原理第三章练习题答案一、选择题1. 在编译原理中,词法分析器的作用是什么?A. 将源代码转换为汇编代码B. 将源代码转换为中间代码C. 识别源代码中的词法单元D. 检查源代码的语法正确性答案:C2. 词法单元中,标识符和关键字的区别是什么?A. 标识符可以重定义,关键字不可以B. 标识符和关键字都是常量C. 标识符是用户自定义的,关键字是语言预定义的D. 标识符和关键字都是变量名答案:C3. 下列哪个不是词法分析器生成的属性?A. 行号B. 列号C. 词法单元的类型D. 词法单元的值答案:A4. 词法分析器通常使用哪种数据结构来存储词法单元?A. 栈B. 队列C. 链表D. 数组答案:C5. 词法分析器的实现方法有哪些?A. 手工编写正则表达式B. 使用词法分析器生成器C. 编写扫描程序D. 所有上述方法答案:D二、简答题1. 简述词法分析器的基本工作流程。

答案:词法分析器的基本工作流程包括:读取源代码字符,根据正则表达式匹配词法单元,生成词法单元的类型和值,并将它们作为输出。

2. 什么是正规文法?它在词法分析中有什么作用?答案:正规文法是一种形式文法,它使用正则表达式来定义语言的词法结构。

在词法分析中,正规文法用于描述程序设计语言的词法规则,帮助词法分析器识别和生成词法单元。

三、应用题1. 给定一个简单的词法分析器,它需要识别以下词法单元:标识符、关键字(如if、while)、整数、运算符(如+、-、*、/)、分隔符(如逗号、分号)。

请描述该词法分析器的实现步骤。

答案:实现步骤如下:- 定义词法单元的类别和对应的正则表达式。

- 读取源代码字符,逐个字符进行匹配。

- 使用状态机或有限自动机来识别词法单元。

- 根据匹配结果生成相应的词法单元类型和值。

- 输出识别的词法单元。

2. 设计一个简单的词法分析器,它可以识别以下C语言关键字:int, float, if, else, while, return。

词法分析器(含完整源码)

词法分析器(含完整源码)
}//error
void Scanner(char ch[],int chLen,Table table[Max],int nLine) {
int chIndex = 0;
while(chIndex < chLen) //对输入的字符扫描 { /**************************处理空格和 tab ************************/
六、总结:
词法分析是构造编译器的起始阶段,也是相应比较简单的一个环节。词法分析的主要任 务是:根据构造的状态转换图,从左到右逐个字符地対源程序进行扫描,识别开源程序中具 有独立含义的最小语法单位——符号或单词,如变量标识符,关键字,常量,运算符,界符 等。
然后将提取出的标识符以内码的形式表示,即用 int 类型的数字来表示其类型和在 display 表中的位置,而无须保留原来标识符本身的字符串,这不仅节省了内存空间,也有 利于下一阶段的分析工作。
typedef struct DisplayTable {
int Index; //标识符所在表的下标 int type; //标识符的类型 int line; //标识符所在表的行数 char symbol[20]; //标识符所在表的名称 }Table;
int TableNum = 0; //display 表的下标 char Word[WordMaxNum][20]; //标识符表 char Digit[WordMaxNum][20]; //数字表 int WordNum = 0; //变量表的下标 int DigNum = 0; //常量表的下标 bool errorFlag = 0; //错误标志
当然,在扫描源程序串的同时,进行一些简单的处理,如删除空格、tab、换行等无效 字符,也进行了一些基本的错误处理,如变量长度的判别,有些不合词法规则的标识符判别 等。总之,严格说来,词法分析程序只进行和词法分析相关的工作。

《编译原理》第三章 词法分析器

《编译原理》第三章 词法分析器

有限自动机模型
Finite Automata (FA):
一个有限自动机的模型如下所示:
... ... head finite control input tape
输入带被分成一个个的小单元来装输入符号, 其右边是无限延伸的。 有限状态控制器由有限个状态组成,并根据读 入字符将当前状态转换成下一个状态
有限自动机与正规式的等价性证明
• 证明一: 对于∑上的NFA M,我们来构造∑上的正规式r, 使得L(r)=L(M)。 首先,我们将状态图的概念拓广,令每条弧可 用正规式作标记。并在M的转换图上加进两个 结点,一个为X,一个为Y。从X用ε弧连接到Y, 从而形成一个新的NFA,记为M’,它只有一个初 态X和一个终态Y。显然L(M)=L(M’)。即,这 两个NFA是等价的。 现在来逐步消去M’中的所有结点,直至只剩下 X和Y为止。
有限自动机接受的语言
The language accepted by FA
一个FA 能够接受的语言定义如下:
• 对于一个 DFA M, 可接受的语言表示为: L(M)={ x | x∈Σ* and f(s0 , x)∈Z} • 对于一个 NFA M, 其接受的语言为: L(M)={x | x∈Σ*and f(s0, x)∩Z≠Φ} • 两个 FA M and M’ 是等价的当且仅当 L(M) = L(M’)
M
M
a
M
假设对于任意 正规式 r1 and r2, 如果 |r1| < k 而 且 |r2| < k, 那么就于一个NFA M1 and M2 对应 于r1 和 r2. 所以对于任意 RE r, |r| = k, 我们有:
• 这个自动机所接受的语言是所有被3整除 以后余数为2的二0, q1, q2, q3}, {0, 1}, f1, q0 {q3} ) . 其中f1如下所示 :

编译原理课程设计教案

编译原理课程设计教案

编译原理课程设计教案一、课程简介1.1 课程背景编译原理是计算机科学与技术领域的基础课程,旨在培养学生对编译器设计和实现的理解。

通过本课程的学习,学生将掌握编译器的基本原理、构造方法和实现技巧。

1.2 课程目标(1)理解编译器的基本概念、工作原理和分类;(2)熟悉源程序的词法分析、语法分析、语义分析、中间代码、目标代码和优化等基本过程;(3)掌握常用的编译器构造方法和技术;(4)能够设计和实现简单的编译器。

二、教学内容2.1 词法分析(1)词法规则的定义和描述;(2)词法分析器的实现方法;(3)词法分析在编译器中的作用和重要性。

2.2 语法分析(1)语法规则的定义和描述;(2)语法分析树的构建方法;(3)常用的语法分析算法及其特点。

2.3 语义分析(1)语义规则的定义和描述;(2)语义分析的方法和技巧;(3)语义分析在编译器中的作用和重要性。

2.4 中间代码(1)中间代码的定义和表示;(2)中间代码的方法和策略;(3)中间代码在编译器中的作用和重要性。

2.5 目标代码和优化(1)目标代码的方法和技巧;(2)代码优化的方法和策略;(3)目标代码和优化在编译器中的作用和重要性。

三、教学方法3.1 讲授法通过讲解编译原理的基本概念、理论和方法,使学生掌握编译器的设计和实现技巧。

3.2 案例分析法分析实际编译器的设计和实现案例,使学生更好地理解编译原理的应用。

3.3 实验法安排实验课程,让学生动手设计和实现简单的编译器组件,提高学生的实际操作能力。

3.4 小组讨论法组织学生进行小组讨论,培养学生的团队合作精神和沟通能力。

四、教学评价4.1 平时成绩包括课堂表现、作业完成情况和小测验成绩,占总评的30%。

4.2 实验成绩包括实验报告和实验演示,占总评的30%。

4.3 期末考试包括理论知识考核和实际操作考核,占总评的40%。

五、教学资源5.1 教材推荐使用《编译原理》教材,为学生提供系统、全面的学习资料。

5.2 课件制作精美、清晰的课件,辅助课堂教学。

词法分析器(含完整源码)

词法分析器(含完整源码)

词法分析实验报告一、实验目的与要求:1、了解字符串编码组成的词的内涵,感觉一下字符串编码的方法和解读2、了解和掌握自动机理论和正规式理论在词法分析程序和控制理论中的应用二、实验内容:构造一个自己设计的小语言的词法分析器:1、这个小语言能说明一些简单的变量识别诸如begin,end,if,while等保留字;识别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。

识别数字序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。

2、相关过程(函数):Scanner()词法扫描程序,提取标识符并填入display表中3、这个小语言有顺序结构的语句4、这个小语言能表达分支结构的语句5、这个小语言能够输出结果总之这个小语言词法分析器能提供以上所说明到的语法描述的功能……三、实验步骤:1、测试评价(1)、测试1:能说明一些简单的变量,如关键字、一般标识符、界符等;(2)、测试2:能输出结果:单词符号(内码形式)、各种信息表(如符号表、常量表等);(3)、测试程序:var x,y,z;beginx:=2;y:=3;if (x+5>=y*y) thenbeginz:=y*y-x;z:=z+x*x;endelsez:=x+y;prn z;end.(4)、结果:①、从键盘读入;部分结果如下:(类型:该标识符所属的类型,如关键字,变量等;下标:该标识符所对应表(如变量标识符表,常量标识符表等)中其相应的位置,下同)②、从文件读入,输出到文件;部分结果如下:其他测试及结果如下:③、出错处理;注:若有错误,则只指出错误,不输出各个表;(5)、评价:这个小语言程序基本上能完成词法分析阶段的工作,识别诸如begin,if等保留字;识别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。

识别数字序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。

简单的C语言编译器--词法分析器

简单的C语言编译器--词法分析器

简单的C语⾔编译器--词法分析器1. 定义词法单元Tag ⾸先要将可能出现的词进⾏分类,可以有不同的分类⽅式。

如多符⼀类:将所有逗号、分号、括号等都归为⼀类,或者⼀符⼀类,将⼀个符号归为⼀类。

我这⾥采⽤的是⼀符⼀类的⽅式。

C代码如下:#ifndef TAG_H#define TAG_Hnamespace Tag {//保留字const intINT = 1, BOOL = 2, MAIN = 3, IF = 4,ELSE = 5, FOR = 6, WHILE = 7, FALSE = 8,BREAK = 9, RETURN = 10, TRUE = 11 ;//运算符const intNOT = 20, NE = 21, AUTOMINUS =22, MINUS = 23,AUTOADD = 24, ADD = 25, OR = 26,AND = 27, MUTIPLY = 28, DIVIDE = 29, MOD = 30,EQ = 31, ASSIN = 32, GE = 33, GT = 34,LE = 35, LS = 36;//分界符const intCOMMA = 40, SEMICOLON = 41, LLBRACKET = 42,RLBRACKET = 43, LMBRACKET = 44, RMBRACKET = 45,LGBRACKET = 46, RGBRACKET = 47;//整数常数const int NUM = 50;//标识符const int ID = 60;//错误const int ERROR = 404;//空const int EMPTY = 70;}#endif2. 具体步骤⼀个⼀个字符地扫描测试代码,忽略空⽩字符,遇到回车时,记录⾏数加1要进⾏区分标识符(即普通变量名字)和保留字因为将标识符和常数都guiwe各⾃归为⼀类,所以要有算法能够识别出⼀整个常数和完整的标识符加⼊适当的⾮法词检测3. 设计词法分析类 设计⼀个词法分析器,当然要包括如何存储⼀个词法单元,如何扫描(scan)测试代码等,直接上代码:myLexer.h#ifndef MYLEXER_H#define MYLEXER_H#include <fstream>#include <string>#include <unordered_map>#include "tag.h"/** 主要是定义基本的词法单元类,* 声明了词法分析类*///存储词法单元class Word {public:Word() = default;Word(std::string s, int t) : lexeme(s), tag(t) {};std::string getLexeme() { return lexeme; };int getTag() { return tag; }void setTag(int t) { tag = t; }void setLexeme(std::string s) { lexeme = s; }private:std::string lexeme;int tag;};//词法分析器类class Lexer {public:Lexer();void reserve(Word w);bool readnext(char c, std::ifstream &in);Word scan(std::ifstream &in);int getLine() { return line; }private:char peek;std::unordered_map<std::string, Word> words;int line;};#endifmyLexer.cpp#include <iostream>#include <cctype>#include <sstream>#include "myLexer.h"void Lexer::reserve(Word w) {words.insert({w.getLexeme(), w});}Lexer::Lexer() {//存⼊保留字,为了区分标识符reserve( Word("int", Tag::INT) );reserve( Word("bool", Tag::BOOL) );reserve( Word("main", Tag::MAIN) );reserve( Word("if", Tag::IF) );reserve( Word("else", Tag::ELSE) );reserve( Word("for", Tag::FOR) );reserve( Word("while", Tag::WHILE) );reserve( Word("break", Tag::BREAK) );reserve( Word("return", Tag::RETURN) );reserve( Word("true", Tag::TRUE) );reserve( Word("false", Tag::FALSE) );peek = ' ';line = 1;}//⽅便处理像>=,++等这些两个字符连在⼀起的运算符 bool Lexer::readnext(char c, std::ifstream &in) {in >> peek;if( peek != c)return false;peek = ' ';return true;}Word Lexer::scan(std::ifstream &in) {//跳过空⽩符while(!in.eof()) {if(peek == ' ' || peek == '\t') {in >> peek;continue;}else if(peek == '\n')++line;elsebreak;in >> peek;}//处理分界符、运算符等switch(peek) {case '!':if(readnext('=', in))return Word("!=", Tag::NE);elsereturn Word("!", Tag::NOT);case '-':if(readnext('-', in))return Word("--", Tag::AUTOMINUS);elsereturn Word("-", Tag::MINUS);case '+':if(readnext('+', in))return Word("++", Tag::AUTOADD);elsereturn Word("+", Tag::ADD);case '|':if(readnext('|', in))return Word("||", Tag::OR);elsereturn Word("error", Tag::ERROR);case '&':if(readnext('&', in))return Word("&&", Tag::AND);elsereturn Word("error", Tag::ERROR);case '*':in >> peek;return Word("*", Tag::MUTIPLY);case '/':in >> peek;return Word("/", Tag::DIVIDE);case '%':in >> peek;return Word("%", Tag::MOD);case '=':if(readnext('=', in))return Word("==", Tag::EQ);elsereturn Word("=", Tag::ASSIN);case '>':if(readnext('=', in))return Word(">=", Tag::GE);elsereturn Word(">", Tag::GT);case '<':if(readnext('=', in))return Word("<=", Tag::LE);elsereturn Word("<", Tag::LS);case ',':in >> peek;return Word(",", Tag::COMMA);case ';':in >> peek;return Word(";", Tag::SEMICOLON);case '(':in >> peek;return Word("(", Tag::LLBRACKET);case ')':in >> peek;return Word(")", Tag::RLBRACKET);case '[':in >> peek;return Word("[", Tag::LMBRACKET);case ']':in >> peek;return Word("]", Tag::RMBRACKET);case '{':in >> peek;return Word("{", Tag::LGBRACKET);case '}':in >> peek;return Word("}", Tag::RGBRACKET);}//处理常数if(isdigit(peek)) {int v = 0;do {v = 10*v + peek - 48;in >> peek;} while(isdigit(peek));if(peek != '.')return Word(std::to_string(v), Tag::NUM);}//处理标识符if(isalpha(peek)) {std::ostringstream b;do {b << peek;in >> peek;} while(isalnum(peek) || peek == '_');std::string tmp = b.str();//判断是否为保留字if(words.find(tmp) != words.end())return words[tmp];elsereturn Word(tmp, Tag::ID);}if(peek != ' ' && peek != '\t' && peek != '\n')return Word("error", Tag::ERROR);return Word("empty", Tag::EMPTY);} 设计完成后,⾃⼰写⼀个Main函数,在while循环中调⽤scan函数,每次打印出Word内容,就能够得到。

一个简单的词法分析器

一个简单的词法分析器

实验一词法分析程序设计与实现一、实验目的:加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。

二、实验内容:自定义一种程序设计语言,或者选择已有的一种高级语言(C语言),编制它的词法分析程序。

词法分析程序的实现可以采用任何一种编程工具。

三、实验要求:1. 对单词的构词规则有明确的定义;2. 编写的分析程序能够正确识别源程序中的单词符号;3. 识别出的单词以<种别码,值>的形式保存在符号表中;4. 词法分析中源程序的输入以.c格式,分析后的符号表保存在.txt文件中。

5. *对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析;6. 实验报告要求用自动机或者文法的形式对词法定义做出详细说明,说明词法分析程序的工作过程,说明错误处理的实现*。

四、实验学时:12学时五、实验步骤:1. 定义目标语言的可用符号表和构词规则;2. 依次读入源程序符号,对源程序进行单词切分和识别,直到源程序结束;3. 对正确的单词,按照它的种别以<种别码,值>的形式保存在符号表中;4. *对不正确的单词,做出错误处理*。

词法分析(Lexical Analysis) 是编译的第一阶段。

词法分析器的主要任务是读入源程序的输入字符、将他们组成词素,生成并输出一个词法单元序列,每个词法单元对应一个词素。

这个词法单元序列被输出到语法分析器进行语法分析。

知识储备词法单元:由一个词法单元名和一个可选的属性值组成。

词法单元名是一个表示某种词法单位的抽象符号,比如一个特定的关键字,或者代表一个标识符的输入字符序列。

词法单元名字是由语法分析器处理的输入符号。

模式:描述了一个词法单元的词素可能具有的形式。

词素:源程序中的一个字符序列,它和某个词法单元的模式匹配,并被词法分析器识别为该词法单元的一个实例。

写一个简单的C词法分析器

写一个简单的C词法分析器

写⼀个简单的C词法分析器写⼀个简单的C词法分析器在写本⽂过程中,我参考了《》中的⼀些内容。

这⾥我们主要讨论写⼀个C语⾔的词法分析器。

⼀、关键字⾸先,C语⾔中关键字有:auto、break、case、char、const、continue、default、do、double、else、enum、extern、float、for、goto、if、int、long、register、return、short、signed、sizeof、static、struct、switch、typedef、unsigned、union、void、volatile、while等共32个关键字。

⼆、运算符C语⾔中的运算符有:(、)、[、]、->、.、!、~、++、--、-、()、*、&、*、/、%、+、-、<<、>>、<、<=、>、>=、==、!=、&、^、|、&&、||、?:、=、+=、-=、*=、/=、%=、&=、^=、|=、<<=、>>=、,、等共45个运算符。

说明:-减号与-负号在词法阶段⽆法判别,需要在语法或予以阶段判别;同理*乘号与*指针操作符也是这样的。

三、界符另外C语⾔还有以下界符:;、{、}、:四、标⽰符C语⾔中标⽰符的定义为:开头可以是下划线或字母,后⾯可以是下划线、字母或数字。

五、常数整形数和浮点数六、空⽩符C语⾔中的空⽩符有:空格符、制表符、换⾏符,这些空⽩符在词法分析阶段可以被忽略。

七、注释C语⾔中的注释形式为:/*…*/,可以多⾏注释。

下⾯我们给出C程序中token和其对应的种别码:单词符号种别码单词符号种别码单词符号种别码auto1union28[55break2unsigned29]56case3void30^57char4volatile31^=58const5while32{59continue6-33|60default7--34||61do8-=35|=62double9->36}63else10!37~64enum11!=38+65extern12%39++66float13%=40+=67for14&41< 68goto15&&42<< 69if16&=43<<=70int17(44<=71long18)45=72sizeof2350>>=77static2451"78struct2552/*注释*/79switch2653常数80typedef2754标识符81我们的词法分析程序根据所给的源代码程序,输出的是⼆元组:<单词符号, 种别码>。

写一个整数四则运算的解析器——词法分析部分

写一个整数四则运算的解析器——词法分析部分

写⼀个整数四则运算的解析器——词法分析部分写⼀个简单的词法、语法分析器,来最终分析出整数四则运算表达式的结果。

为了简化词语法分析我们只允许出现0~9,+,-,*,/,空格,\r, \n这⼏个字符词法分析:⽅法1. 状态机我们先准备3个判断⽅法:// 是否是数字function isNum(letter) {return letter === '0' || letter === '1' || letter === '2' || letter === '3' || letter === '4' || letter === '5' || letter === '0' || letter === '6' || letter === '7' || letter === '8' || letter === '9' }// 是否是运算符function isOperater(letter) {return letter === '+' || letter === '-' || letter === '*' || letter === '/'}// 是否是间隔符function isEmptyLetter(letter) {return letter === ' ' || letter === '\r' || letter === '\n'}定义⽣成token的函数:const tokenList = []function generateToken(type, token) {console.log("⽣成token: " + token);tokenList.push({type, token});}定义状态转移函数:let token = []function startToken(letter) {if (isNum(letter)) {// 如果是数字,则进⼊inNumber状态token.push(letter)return inNumber} else if (isOperater(letter)) {// 如果是+-*/, 就马上⽣成⼀个tokengenerateToken(letter, letter)return startToken} else if (isEmptyLetter(letter)) {// 如果是空⽩字符,则跳过return startToken} else {// 如果是其他字符则报错throw new Error('出现意外字符')}}function inNumber(letter) {if (isNum(letter)) {token.push(letter)return inNumber} else {// 直到遇到⾮数字, 把前⾯push的数字⽣成⼀个数字token, 然后清空tokengenerateToken('number', token.join(''))token = []// 最后让新的letter马上执⾏⼀次startTokenreturn startToken(letter)}}开始词法分析:// 要词法分析的字符串const str = '123* 656 - 644 + 3131'// 分割成⼀个个字母let strArr = str.split('');// 定义状态机let state = startToken// 遍历字母,不停地更新状态机for(let letter of strArr) {state = state(letter)}// 结束state(Symbol('EOF'))generateToken('EOF', 'EOF')得出结果:⽅法2. 正则分析// 要词法分析的字符串let str = '123* 656 - 644 + 3131'// 过滤间隔符str = str.replace(/[\r\n ]/g, '')const operatorRegExp = /[+\-*/]/g// 获取运算的数字tokenlet numList = str.split(operatorRegExp)// 获取运算符tokenlet operatorList = str.match(operatorRegExp)const tokenList = []numList.forEach((item, idx) => {tokenList.push({type: 'number', token: item})if (idx !== numList.length - 1) {tokenList.push({type: operatorList[idx], token: operatorList[idx]}) }})// 结束tokenList.push({type: 'EOF', token: 'EOF'})console.log(tokenList)得出结果:到这⾥词法分析就已经完成了。

编译原理-词法分析器-仅供参考-不可滥用!

编译原理-词法分析器-仅供参考-不可滥用!

青岛理工大学课程实验报告课程名称编译原理班级实验日期姓名未名学号实验成绩实验名称实验一词法分析实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。

实验要求1. 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。

(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。

空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。

2.各种单词符号对应的种别码:表2.1 各种单词符号对应的种别码单词符号种别码单词符号种别码bgin 1 :17If 2 := 18Then 3 < 20wile 4 <> 21do 5 <= 22end 6 > 23 lettet(letter|digit)* 10 >= 24 dight dight* 11 = 25 + 13 ;26—14 ( 27* 15 ) 28/ 16 # 0++ 1313 !31-- 1414 != 3125== 2525 可继续扩充…3. 词法分析程序的功能:输入:所给文法的源程序字符串。

输出:二元组(syn,token或sum)构成的序列。

其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。

例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,‘x’)(18,:=)(11,9)(26,;)(2,if)……实验环境1.Visual C++6.02.Win7/Windows XP实验内容根据实验要求,设计一个词法分析器,能根据不同的程序,进行分析,获得各标识符的分类表示。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2014-9-26 17





(5) 若作为一个主程序,须加一层while循环控制: while (1= =1) { token= ' '; /*对token数组初始化*/ getchar( ); getbe( ); /*滤除空格…*/ if (character!=EOF) { switch (character) … } else break; /* end of if */ } /*end of while */
2014-9-26 14
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;
大多数程序语言的单词符号都可用 状态转换图予以识别。下面构造一个 C 语言子集的简单词法分析器,该 C 语言 子集的所有单词符号及其种别编码和内 码值如下表所示。 由于直接使用整数编码不利于记忆, 故采用一些助记符表示种别编码。
2014-9-26 3
表2.1 C语言子集的单词符号及内码值 单词符号 种别编码 while 1 if 2 else 3 switch 4 case 5 6 标识符 7 常数 + 8 − 9 * 10 <= 11 < 11 == 11 = 12 13 ;
2014-9-26
13
case '0': case '1': … case '9': while (digit ( )) { concatenation ( ); getchar ( ); } retract ( ); buildlist ( ); /*将常数登录到常数表中*/ return (num, num的常数表入口指针); break;
2014-9-26 9
(4)concatenation( ): 将token中字符串与 character中字符连接作为token中的新 字符串。 (5)letter( )和digit( ): 判断character中的字 符是否为字母和数字的布尔函数,若是 则返回true, 否则返回false。 (6)reserve( ): 按token数组中的字符串查 保留字表, 若是保留字则返回其编码, 否则返回0。
2014-9-26 15
case '=': getchar ( ); if (character=='=') return(relop,EQ); else { retract ( ); return ('=', _ ); } break; case ';': return (';', -); break; default: error ( ); }
2014-9-26 19
2014-9-26
20
编 译 原 理 Principle of Compiling14-9-26 1
2.2 一个简单的词法分析器示例

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

2.2.3 状态转换图的实现
2014-9-26
2
2.2.1 C语言子集的单词符号表示
的字符送入token数组*/
12
}
2014-9-26
retract ( ); /*扫描指针回退一个字符*/ c=reserve ( ); if (c==0) { buildlist ( ); /*将标识符登录到符号表*/ return (id, id在符号表中的入口指针); } else return (保留字码, null) ; break;
2014-9-26 5

对保留字专设对应的状态转换图:

C语言子集对应的状态转换图如下:
6
2014-9-26
空白 字母或数字
开始 0
字母 1 非字母数字 2 * 返回(id, id在符号表中位置)
数字 数字 3 4 * 非数字 + 5 - 6 * < = ; 其它
2014-9-26
或返回(保留字, -)
2014-9-26 18









(6) 考虑不使用retract()、不回退字符,每次情况处 理后多读一个字符留下次直接进行判断处理。 getchar( ); while (1= =1) { token= ' '; /*对token数组初始化*/ getbe( ); /*滤除空格…*/ if (character!=EOF) { switch (character) … /* 去掉每条retract()语句;没有 retract()的case情况加一个getchar();*/ } else break; /* end of if */ } /*end of while */
返回(num, num在常数表中位置) 返回(+, -) 返回(-, -)
7 8
11

其它
返回(*, -)
9 返回(relop, LE) 返回(relop, EQ) 返回(=, -) 返回(; , -) 非法字符错 10 * 返回(relop, LT)

其它
12
13 *
14
15
*
7
注意: (1) 状态 2 识别出一个单词符号后需先 查保留字表 , 若匹配则为保留字 , 否则为标 识符。若为标识符 , 还需查符号表 , 看表中 是否有此标识符。若符号表中无此标识符, 则先将它登录到符号表中,再返回它在符号 表中入口地址作为内码值;若表中有此标识 符,则直接返回其入口地址作为内码值。 (2) 状态 4 识别出一个常数后可以将它 转换成二进制常数再登录到常数表,然后返 回它在常数表中的入口指针作为内码值。
2014-9-26 11
C语言子集对应的的词法分析器如下: token= ' '; /*对token数组初始化*/ getchar( ); getbe( ); /*滤除空格*/ switch (character) { case 'a': … case 'z': while (letter ( )‖digit ( )) { concatenation ( ); /*将当前读入 getchar ( );
2014-9-26
助记符 while if else switch case id num + − * relop relop relop = ;
id在符号表中位置
num在常数表中位置
内码值 — — — — —
— — — LE LT EQ — —
4
2.2.2 C语言子集对应的状态转换图的设计 首先对输入串做预处理。 即剔除多余的空格、注释、制表符和 换行符等。 其次把保留字作为一类特殊标识符处理。 即对保留字不专设对应的状态转换图, 当状态转换图识别出一个标识符时就去查 表,确定它是否为一个保留字。
2014-9-26 10
(7) retract( ): 扫描指针回退一个字符, 同
时将character置为空白。
(8)buildlist( ): 将标识符登录到符号表或将常数
登录到常数表;若登录表中已存在该标识符
或常数,则返回相关信息。
(9)error( ): 进行出错处理。
(10)getchar():把下一个输入字符读到character中, 读入源程序字符的指针前移一个字符。
2014-9-26 16
注意:编程实现过程中, (1)return(…):该程序作为语法分析的子 程序,返回相关信息给语法分析程序; 若单独作为一个主程序,return当作print 相关信息。 (2)getbe():可增加功能:跳过注释、制 表符和换行符等,碰到换行符则 LineNo (记录行号的变量)增加1。 (3)error():利用LineNo,可告诉用户错误 所在的行号,并适当提供纠错信息。 (4)增加功能:识别含“_”的标识符、无 符号小数、无符号数、符号数(负号)。
2014-9-26 8
2.2.3 状态转换图的实现 状态转换图易于用程序实现,最简单的 办法是让每个状态对应一小段程序。对于 图2–5,首先引进一组变量和过程: (1)character: 字符变量,存放最新读入 的源程序字符。 (2)token: 字符数组,存放构成单词符号 的字符串。 (3)getbe( ): 若character中字符为空,则 调用getchar( ),直至character为非空。
相关文档
最新文档