实验一词法分析

合集下载

实验1 词法分析

实验1 词法分析

实验1 词法分析一、目的与要求1)目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课 堂教学的理解;提高词法分析方法的实践能力。

2)要求u掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文 件的方法。

u掌握词法分析的实现方法。

u上机调试编出的词法分析程序。

二、说明本实验以赋值语句(以#号表示输入结束)为输入文件,BNF表示如下:〈赋值语句〉 ∷= 变量 = 算术表达式〈算术表达式〉∷=〈项〉〈算术表达式〉∷=〈算术表达式〉+〈项〉〈算术表达式〉∷=〈算术表达式〉-〈项〉〈项〉∷=〈因式〉〈项〉∷=〈项〉*〈因式〉〈项〉∷=〈项〉/〈因式〉〈因式〉∷=〈变量〉〈因式〉∷=(〈算术表达式〉)〈变量〉::= 标识符|常整数字母表:Σ={+,­,*,\,(,),=,a,b,c….z,A,B,C…Z,0,1,2,…9,#} 单词类型:u标识符 :字母组成,长度不限u常整数 :数字组成u运算符 :+,-,*,\,()u结束符:#数据结构: 标识符用单独的符号表来记录,符号表中标识符的属性只有一项: 标识符本身的字符串值。

输出:二元式,第一部分为单词的类别,第二部分为单词的属性值,其中标识 符的属性值为标识符表的索引值,常整数的属性值为常整数值,其他的属性值为单 词本身的字符串值三、词法分析过程1、背景知识(对源程序或中间结果从头到尾扫 词法分析是作为相对独立的阶段来完成的描一次,并作相应的加工处理,生成新的中间结果或目标程序)。

在词法分析 过程中,编译程序是通过操作系统从外部介质中读取源程序文件中的各个字符 的。

同时,为正确地识别单词,有时还需进行超前搜索和回退字符等操作。

因 此,为了提高读盘效率和便于扫描器进行工作,通常可采用缓冲输入的方案, 即在内存中设置一个适当大小的输入缓冲区,让操作系统直接将磁盘上的源程 序字符串分批送入此缓冲区中,供扫描器进行处理。

词法分析程序的一般设计方案是:1) 程序设计语言词法规则⇒正规文法⇒ FA;或:词法规则⇒正规表达式⇒ FA;2) NFA 确定化⇒ DFA;3) DFA 最简化;4) 确定单词符号输出形式;5) 化简后的DFA+单词符号输出形式⇒构造词法分析程序。

实验一词法分析

实验一词法分析

编译原理实验一词法分析1.实验目的通过实验掌握词法分析的理论、原理和方法,为语法分析做准备。

2.实验内容:a)十六进制数识别器:规定是:必须以十六进制数字打头,以H结尾,十六进制数中允许使用的数字为0-9,字母为A,B,C,D,E, F(分别表示0~15)。

试设计一个DFA,使它能识别无符号的十六进制整数,并编制相应的识别程序。

输入:学生自行确定符号串的输入形式,如键盘输入、文本文件、字符数组等。

输出:标识出规范的符号串与不合规范的符号串。

b)词法分析:设计、编制、调试一个识别一个Little语言单词的词法分析程序(见附录1)。

输入:学生自行确定符号串的输入形式,如键盘输入、文本文件、字符数组等。

输出:二元组。

3.实验要求:(1)上机前编写完整的实验报告,报告中要体现分析→设计→实现等几个过程;如无实验报告,则取消本次上机资格,实验成绩以0分记。

(2)严禁相互抄袭,否则实验成绩以0分记;(3)有完整的源代码,源码有规范的注释,无明显的语法错误;4.实验步骤(1)分析与设计a、文法:该语言的十六进制,如:0aH,77H,7BH等由以数字打头及以H结尾;该语言的标识符,如:Num,a3,go等由A到Z(or a到z)和0至9所组成;该语言的无符号的十进制,如:8,90,123等由0到9之间的任意数字组成。

由以上可得出该语言的文法可表示如下:G(S) = (VN,VT,P,S)其中VN={S,X’,Y’,Z’,M’,W’,α,β,γ,μ,υ,ω}VT= {0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}α= 0|1| 2|3|4|5|6|7|8|9β= a|b|c|d|e|f|A|B|C|D|E|Fγ=g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|G|H|I|G|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|ZS →X’|Y’|Z’X’→υ|υM’M’→ω|ωM’υ→β|γω→α|β|γY’→α|αY’Z’→αH|αW’HW’→μ|μW’μ→α|β可见,上式方法中,X’表示出了语言的标识符,而Y’表示出了语言的无符号的十进制,Z’表示出了语言中的十六进制。

实验1 词法分析实验报告

实验1  词法分析实验报告
{
p=0;
row=1;
cout<<"Please input string:"<<endl;
do
{
cin.get(ch);
prog[p++]=ch;
}
while(ch!='#');
p=0;
do
{
scaner();
switch(syn)
{
case 11: cout<<"("<<syn<<","<<sum<<")"<<endl; break;
实验二时发现怎么出结果都会出现一个缺:=错误,便回头检查代码才发现实验一时的scaner()函数最后的:和:=的种别码互相写错了,所以回过头来重新修正了代码和实验结果图。
case -1: cout<<"Error in row"<<row<<"!"<<endl; break;
case -2: row=row++;break;
default: cout<<"("<<syn<<","<<token<<")"<<endl;break;
}
}
while (syn!=0);
}
四、结果验证
{
syn=21;
token[m++]=ch;
}
else if(ch=='=')

实验一 词法分析

实验一  词法分析

实验一词法分析1.实验要求(1)从源程序文件中读取有效字符并将其转换成二元组内部表示形式输出。

(2)掌握词法分析的实现方法。

(3)实验时间4学时。

(4)实验完成后,要提交实验报告(包括源程序清单)。

2.实验内容2.1主程序设计考虑:主程序的说明部分为各种表格和变量安排空间(关键字和特殊符号表)。

id 和ci 数组分别存放标识符和常数;还有一些为造表填表设置的变量。

主程序的工作部分建议设计成便于调试的循环结构。

每个循环处理一个单词;调用词法分析过程;输出每个单词的内部码(种别编码,属性值)。

建议从文件中读取要分析的符号串。

2.2词法分析过程考虑该过程根据输入单词的第一个有效字符(有时还需读第二个字符),判断单词种别,产生种别编码。

对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组id 中,将三:主流程图如下:四:实验思路(1)我首先把这个单词的种类分成了五类,包括:关键字、标识符、常数、算符、界符。

然后利用状态转换图进行单词的识别(2)对于关键字、算符、界符。

因为这些单词的个数有限。

所以我单独给每个单词一个种别编码。

能够做到每个单词的种别编码是不一样的。

而对于常数和标识符,我先把它们分别单独的作为一类,然后定义一个二维数组,分别存放这个单词的名称和编码。

而这个编码就是这个单词在这个二维数组中的位置;当遇到新的标识符或常数,就把这个单词放入到相应的数组中。

(3)然后构造一个状态转换图的程序。

把每次得到的单词先暂时存放在temp 二维数组中。

然后用这个临时的二维数组去确定这个单词是何种类别五:实验代码using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace Word{public partial class Form1 : Form{public Form1(){InitializeComponent();}char[] receive; //从输入得到的源程序char ch; //这是从源程序读取的一个字符string cache; //暂存的单词int index; //记录取到哪个位置了key_word temp; //用来临时存放得到这个单词struct key_word{public string key_name;public int number;}struct num_word{public string num_name;public int number;}struct ID_word{public string ID_name;public int number;}public int num_index;public int ID_index;DataTable dt;private void button1_Click(object sender, EventArgs e){dt = new DataTable();dt.Columns.Add("助记符");dt.Columns.Add("外部编码");dt.Columns.Add("内部编码");dt.Columns.Add("类型");receive = textBox1.Text.ToCharArray();index = 0;num_index = 0;ID_index = 0;;while (index < receive.Length){cache = null;Get_Word();if (temp.number == 1){int i = 0;int flag = 0;if (num_index == 0){Num[num_index].num_name = temp.key_name;Num[num_index].number = num_index;num_index++;}else{for (i = 0; i < num_index; i++){if (Num[i].num_name == temp.key_name){flag = i;break;}}if (i >= num_index){Num[num_index].num_name = temp.key_name;Num[num_index].number = num_index;flag = num_index;num_index++;}}DataRow dr = dt.NewRow();dt.Rows.Add(dr);dr["助记符"] = temp.key_name;dr["内部编码"] = +Num[flag].number;dr["类型"] = "常数";}else if (temp.number == 0){int i = 0;int flag = 0;if (ID_index == 0){ID[ID_index].ID_name = temp.key_name;ID[ID_index].number = ID_index;ID_index++;}else{for (i = 0; i < ID_index; i++){if (ID[i].ID_name == temp.key_name){flag = i;break;}}if (i >= ID_index){ID[ID_index].ID_name = temp.key_name;ID[ID_index].number = ID_index;flag = ID_index;ID_index++;}}DataRow dr = dt.NewRow();dt.Rows.Add(dr);dr["助记符"] = temp.key_name;dr["外部编码"] = temp.number;dr["内部编码"] = ID[flag].number;dr["类型"] = "标识符";}else{DataRow dr = dt.NewRow();dt.Rows.Add(dr);dr["助记符"] = temp.key_name;if (temp.number >= 15 && temp.number <= 30){dr["类型"] = "运算符";}else if (temp.number >= 31 && temp.number <= 40){dr["类型"] = "界符";}else{dr["类型"] = "关键字";}}}this.dataGridView1.DataSource = dt;}key_word[] Key;num_word[] Num;ID_word[] ID;private void Form1_Load(object sender, EventArgs e){index = 0;Key = new key_word[41];Key[0].key_name = "$ID"; Key[0].number = 0; //标识符Key[1].key_name = "$INT"; Key[1].number = 1; //数Key[2].key_name = "int"; Key[2].number = 2; Key[3].key_name = "float"; K ey[3].number = 3;Key[4].key_name = "void"; Key[4].number = 4; Key[5].key_name = "const"; Key[5].number = 5; Key[6].key_name = "if"; Key[6].number = 6; Key[7].key_name = "el se"; Key[7].number = 7;Key[8].key_name = "do"; Key[8].number = 8; Key[9].key_name = "while"; Key[9].number = 9; Key[10].key_name = "scanf"; Key[10].number = 10; Key[11].key_nam e = "printf"; Key[11].number = 11;Key[12].key_name = "return"; Key[12].number = 12; Key[13].key_name = " main"; Key[13].number = 13; Key[14].key_name = "read"; Key[14].number = 14;Key[15].key_name = "+"; Key[15].number = 15;Key[16].key_name = "-"; Key[16].number = 16; Key[17].key_name = "*"; K ey[17].number = 17; Key[18].key_name = "/"; Key[18].number = 18; Key[19].key_name = "%"; Key[19].number = 19;Key[20].key_name = "="; Key[20].number = 20; Key[21].key_name = "=="; Key[21].number = 21; Key[22].key_name = ">"; Key[22].number = 22; Key[23].key_name = "<"; Key[23].number = 23;Key[24].key_name = "!="; Key[24].number = 24; Key[25].key_name = ">="; Key[25].number = 25; Key[26].key_name = "<="; Key[26].number = 26; Key[27].key_na me = "&&"; Key[27].number = 27;Key[28].key_name = "||"; Key[28].number = 28; Key[29].key_name = "!"; K ey[29].number = 29; Key[30].key_name = "<>";Key[30].number = 30;Key[31].key_name = "("; Key[31].number = 31;Key[32].key_name = ")"; Key[32].number = 32; Key[33].key_name = "{"; K ey[33].number = 33;Key[34].key_name = "}"; Key[34].number = 34; Key[35].key_name = ";"; K ey[35].number = 35;Key[36].key_name = ","; Key[36].number = 36; Key[37].key_name = "\""; K ey[37].number = 37; Key[38].key_name = "'"; Key[38].number = 38; Key[39].key_name = "++"; Key[39].number = 39;Key[40].key_name = "--"; Key[40].number = 40;Num = new num_word[1024];ID = new ID_word[1024];}public void GetChar() //得到一个字符{if (index < receive.Length){ch = receive[index];index++;}else{ch = '\0';}}public void GetNotKong() //得到一个不是空的字符{while (index < receive.Length){ch = receive[index];index++;if (ch != ' ' && ch != '\r' && ch != '\0' && ch != '\n'){break;}}}public void ConCat() //连接{cache += ch;}public bool IsLetter() //判断是不是字母{if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {return true;}else{return false;}}public bool IsDigit() //判断是不是数字{if (ch >= '0' && ch <= '9'){return true;}else{return false;}}public int Get_Number() //得到这个单词的编码{for (int i = 0; i < 41; i++){if (string.Equals(cache, Key[i].key_name)){return Key[i].number;}}{return 0;}}public void retrace() //退回一个单词{if (ch != '\0'){index--;}private void Get_Word(){int count;GetNotKong();if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {ConCat();GetChar();while (IsLetter() || IsDigit()){ConCat();GetChar();}retrace();count = Get_Number();temp.key_name = cache;if (count == 0){temp.number = 0;}else{temp.number = Key[count].number;}}else if (ch >= '0' && ch <= '9'){ConCat();GetChar();while (IsDigit()){ConCat();GetChar();}retrace();temp.key_name = cache;temp.number = 1;}else if (ch == '+')ConCat();GetChar();if (ch == '+'){ConCat();temp.key_name = cache;temp.number = 39;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '-'){ConCat();GetChar();if (ch == '-'){ConCat();temp.key_name = cache;temp.number = 40;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '<'){ConCat();GetChar();if (ch == '='){ConCat();temp.key_name = cache;temp.number = 26;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '>'){ConCat();GetChar();if (ch == '='){ConCat();temp.key_name = cache;temp.number = 25;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '='){ConCat();GetChar();if (ch == '='){ConCat();temp.key_name = cache;temp.number = 21;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '!'){ConCat();GetChar();if (ch == '='){ConCat();temp.key_name = cache;temp.number = 24;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '&'){ConCat();GetChar();if (ch == '&'){ConCat();temp.key_name = cache;temp.number = 27;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else if (ch == '|'){ConCat();GetChar();if (ch == '|'){ConCat();temp.key_name = cache;temp.number = 28;}else{retrace();temp.key_name = cache;temp.number = Get_Number();}}else{ConCat();temp.key_name = cache;temp.number = Get_Number();}}}}六:实验截图(1)我测试的程序为void main(){ int a=20;int b=15;if(a==20)printf("A");if(b==20)printf("B");}七:实验心得通过这次实验、我对于词法分析需要做的任务有了一个更加深刻的理解。

编译原理词法分析实验报告1

编译原理词法分析实验报告1

实验1 词法分析实验报告一、实验目的调试并完成一个词法分析程序,加深对词法分析原理的理解。

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

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

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

2、各种单词符号对应的种别码3、词法分析程序的功能输入:所给文法的源程序字符串。

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

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

三、源程序代码:#include<stdio.h>#include<string.h>#include<iostream.h>char prog[80],token[8];char ch;int syn,p,m=0,n,row,sum=0;char *rwtab[6]={"begin","if","then","while","do","end"};void scaner(){for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' '){ch=prog[p];p++;}if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){m=0;while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){token[m++]=ch;ch=prog[p++];}token[m++]='\0';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')){{sum=0;while((ch>='0'&&ch<='9')){sum=sum*10+ch-'0';ch=prog[p++];}}p--;syn=11;if(sum>32767)syn=-1;}else switch(ch){case'<':m=0;token[m++]=ch;ch=prog[p++];if(ch=='>'){syn=21;token[m++]=ch;}else if(ch=='=')syn=22;token[m++]=ch;}else{syn=23;p--;}break;case'>':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=24;token[m++]=ch;}else{syn=20;p--;}break;case':':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=18;token[m++]=ch;}else{syn=17;p--;break;case'*':syn=13;token[0]=ch;break;case'/':syn=14;token[0]=ch;break;case'+':syn=15;token[0]=ch;break;case'-':syn=16;token[0]=ch;break;case'=':syn=25;token[0]=ch;break;case';':syn=26;token[0]=ch;break;case'(':syn=27;token[0]=ch;break;case')':syn=28;token[0]=ch;break;case'#':syn=0;token[0]=ch;break;case'\n':syn=-2;break;default: syn=-1;break;}}void main(){p=0;row=1;cout<<"Please input string:"<<endl;do{cin.get(ch);prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){case 11: cout<<"("<<syn<<","<<sum<<")"<<endl; break;case -1: cout<<"Error in row "<<row<<"!"<<endl; break;case -2: row=row++;break;default: cout<<"("<<syn<<","<<token<<")"<<endl;break;}}while (syn!=0);}。

实验一 词法分析

实验一 词法分析

实验一词法分析一、实验目的:通过本实验理解词法分析的整个过程,处理对象和处理的结果,了解词法分析在整个编译过程中的作用。

二、实验学时:2学时。

三、实验内容根据给出的简单语言的词法构成规则和单词集合,编制词法分析程序,要求能用给定的简单语言书写的源程序进行词法分析,同时建立相应的符号表文件存放正确的单词。

输出分析结果于文件中,包括:(1)正确的单词符号及其单词种类的序对二元组。

具体输出形式为:二元组:(单词种类,单词内码值)单词种类见五。

四、实验方法构造识别单词集的自动机,编写程序实现。

五、实验的处理单词集六、处理程序例和处理结果例例1:源程序:main(){y=x-1;}处理结果:(26,"main")(1,"(")(2,")")(3,"{")(0,"y")(6,"=")(0,"x")(100,"-")(20,"1")(5,";")(4,")")例2:源程序main(){int a,b;b!=a-1;}处理结果:(26,"main")(1,"(")(2,")")(3,"{" })(21,”int”)(0,"a")(11,",")(0,"b")(5,”;”)(0,"b")(100,"! ")(6,"=")(0,"a")(100,"-")(30,"1")(5,”;”)(4,”}”)七、实验报告要求给出单词识别的状态转换图;带有注释(简单说明)的源程序。

词法分析设计实验报告(附代码)

词法分析设计实验报告(附代码)

实验一词法分析设计实验学时:4实验类型:综合实验要求:必修一、实验目的通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用。

二、实验容用VC++/VB/JAVA语言实现对C语言子集的源程序进行词法分析。

通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示;同时进行标识符登记符号表的管理。

以下是实现词法分析设计的主要工作:(1)从源程序文件中读入字符。

(2)统计行数和列数用于错误单词的定位。

(3)删除空格类字符,包括回车、制表符空格。

(4)按拼写单词,并用(码,属性)二元式表示。

(属性值——token的机表示) (5)如果发现错误则报告出错(6)根据需要是否填写标识符表供以后各阶段使用。

单词的基本分类:◆关键字:由程序语言定义的具有固定意义的标识符。

也称为保留字例如if、for、while、printf ;单词种别码为1。

◆标识符:用以表示各种名字,如变量名、数组名、函数名;◆常数:任何数值常数。

如125, 1,0.5,3.1416;◆运算符:+、-、*、/;◆关系运算符:<、<=、= 、>、>=、<>;◆分界符:;、,、(、)、[、];三、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。

2、将标识符填写的相应符号表须提供给编译程序的以后各阶段使用。

3、根据测试数据进行测试。

测试实例应包括以下三个部分:◆全部合法的输入。

◆各种组合的非法输入。

◆由记号组成的句子。

4、词法分析程序设计要求输出形式:例:输入VC++语言的实例程序:If i=0 then n++;a﹤= 3b %);输出形式为:单词二元序列类型位置(行,列)(单词种别,单词属性)for (1,for ) 关键字(1,1)i ( 6,i ) 标识符(1,2)= ( 4,= ) 关系运算符(1,3)0 ( 5,0 ) 常数(1,4)then ( 1,then) 关键字(1,5)n (6,n ) 标识符(1,6)++ Error Error (1,7);( 2, ; ) 分界符(1,8)a (6,a ) 标识符(2,1)﹤= (4,<= ) 关系运算符(2,2)3b Error Error (2,4)% Error Error (2,4)) ( 2, ) ) 分界符(2,5);( 2, ; ) 分界符(2,6)实验报告正文:◆功能描述:该程序具有词法分析功能,即面对一段程序源代码,通过该程序,能检查出源代码是否由词法错误。

实验1 词法分析

实验1 词法分析

实验一词法分析一、实验目的编制一个词法分析程序,加深对词法分析原理的理解。

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

(2)运算符和界符. + - * / = <> < <= > >= ( ) ; :=(3)其他单词是标识符(IDENT)和整型常数(NUMBER),通过以下正规式定义:IDENT ::= letter (letter | digit)*NUMBER ::= digit digit*注:所有的IDENT和NUMBER的长度不超过20(4)空格有空白、制表符和换行符组成。

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

整个程序串长度不超过80个字符。

2.各种单词符号对应的类别值:表各种单词符号对应的类别码3. 词法分析程序的功能:输入:所给文法的源程序字符串,以“.”结束。

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

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

对于数值串需要转化为实际的值。

示例:源程序: begin x:=9;if x<10 then x:=(x+10)*2 end.经过词法分析后输出如下序列:(15,begin)(21,x)(14,:=)(22,9)(13,;)……4. 词法分析程序的设计1)词法分析识原理采用状态转换图方法:三、实验说明1、程序中的关键变量,识别示例2、Symbol : 自定义的enum 枚类类型,定义了程序中所有单词符号及其对应类别码。

1) 获得某个字符串(例:begin )的单词符号类型假设strToken= "begin",则:一种方法是直接赋值:sym=symbol.beginsym;另一种方法是通过getType 函数:symbol.getType(strToken.concat("sym")); 2) 获得某sym 的类别码,则可以访问其成员变量sym.iIndex。

词法分析实验报告及完整代码和运行结果

词法分析实验报告及完整代码和运行结果

编译原理实验报告实验一词法分析班级:软件五班学号:姓名:任课教师:邢计算机科学与工程系2016年6 月10 日一、实验目的通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。

并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。

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

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

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

2、各种单词符号对应的种别码3、词法分析程序的功能输入:所给文法的源程序字符串。

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

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

例如:对源程序begin x:=9;if x>0 then x:=2*x+1/3;end#的源文件,经词法分析后输出如下序列:(1,begin)(10,’x’)(18,:=)(11,9)(26,;)(2,if)…4、至少应有3个实例,其中应有一个错误的实例。

遇到词法分析错误时,应能及时报错,并继续分析,直到源程序结束。

三、实验内容编写的词法分析器能将输入的一段源程序中的逐个关键字(begin、if、then、while、do、end)、运算符和界符(:=、+、-、*、/、<、<=、!=、>、>=、==、(、)、;、#)、标示符和整型常数依次识别出来,并且能跟其种别码一一对应。

四、算法设计和源程序#include <stdio.h>#include <stdlib.h>#include <string.h>#define _KEY_WORD_END "waiting for you expanding"typedef struct{int typenum;char * word;}WORD;char input[255];char token[255]="";int p_input;int p_token;char ch;char * rwtab[]={"begin","if","then","while","do","end",_KEY_WORD_END}; WORD* scaner();void main(){int over=1;WORD* oneword=new WORD();printf("Enter Y our words(end with #):");scanf("%[^#]s",input);p_input=0;printf("Y our words:\n%s\n",input);while(over<100&&over!=0){oneword=scaner();if(oneword->typenum<100)printf("(%d,%s)",oneword->typenum,oneword->word);over=oneword->typenum;}printf("\npress # to exit:");scanf("%[^#]s",input);}/*需要用到的自编函数参考实现*//*从输入缓冲区读取一个字符到ch中*/char m_getch(){ch=input[p_input];p_input=p_input+1;return (ch);}/*去掉空白符号*/void getbc(){while(ch==' '||ch==10){ch=input[p_input];p_input=p_input+1;}}/*拼接单词*/void concat(){token[p_token]=ch;p_token=p_token+1;token[p_token]='\0';}/*判断是否字母*/int letter(){if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return 1; else return 0;}/*判断是否数字*/int digit(){if(ch>='0'&&ch<='9')return 1;else return 0;}/*检索关键字表格*/int reserve(){int i=0;while(strcmp(rwtab[i],_KEY_WORD_END)){ if(!strcmp(rwtab[i],token)){return i+1;}i=i+1;}return 10;}/*回退一个字符*/void retract(){p_input=p_input-1;}/*数字转换成二进制,请读者自己补全*/char* dtb(){return NULL;}/*词法扫描程序*/WORD* scaner(){WORD* myword=new WORD; myword->typenum=10;myword->word="";p_token=0;m_getch();getbc();if(letter()){while(letter()||digit()){concat();m_getch();}retract();myword->typenum=reserve();myword->word=token;return(myword);}else if(digit()){while(digit()){concat();m_getch();}retract();myword->typenum=20;myword->word=token;return(myword);}else switch(ch){case '=':m_getch();if(ch=='='){myword->word="==";return(myword);}retract();myword->typenum=25;myword->word="=";return(myword);break;case '+':myword->typenum=13;myword->word="+";return(myword);break;case '-': myword->typenum=14;myword->word="-";return(myword);break;case '*': myword->typenum=15;myword->word="*";return(myword);break;case '/':myword->typenum=16;myword->word="/";return(myword);break;case '(': myword->typenum=27;myword->word="(";return(myword);break;case ')': myword->typenum=28;myword->word=")";return(myword);break;myword->word="[";return(myword);break;case ']': myword->typenum=29;myword->word="]";return(myword);break;case '{': myword->typenum=30;myword->word="{";return(myword);break;case '}': myword->typenum=31;myword->word="}";return(myword);break;case ',': myword->typenum=32;myword->word=",";return(myword);break;case ':': m_getch();if(ch=='='){myword->typenum=18;myword->word=":=";return(myword);}retract();myword->typenum=17;myword->word=":";return(myword);break;case ';':myword->typenum=26;myword->word=";";return(myword);break;case '>':m_getch();if(ch=='='){myword->typenum=24;myword->word=">=";return(myword);}retract();myword->typenum=23;myword->word=">";return(myword);break;case '<':m_getch();if(ch=='='){myword->typenum=22;myword->word="<=";return(myword);}if(ch=='>'){myword->typenum=21;myword->word="<>";return(myword);}retract();myword->typenum=20;myword->word="=";return(myword);break;case '!': m_getch();if(ch=='='){myword->typenum=40;myword->word="!=";return(myword);}retract();myword->typenum=-1;myword->word="ERROR";return(myword);break;case '\0':myword->typenum=1000;myword->word="OVER";return(myword);break;default: myword->typenum=-1;myword->word=&ch;return(myword);}}五、实验结果分析正确的实例1正确的实例2正确的实例3错误的实例对于语法分析方面有了更深层次的了解,。

[实验1] 词法分析

[实验1] 词法分析

[实验1] 词法分析《编译原理》课程实验实验1实验1 词法分析1.实验说明实验题目:词法分析器的设计与实现实验目的:加深对词法分析基本理论的理解,锻炼实现词法分析器程序的实践能力。

实验过程:(1)按照给定的表达式的词法要求,构造分DFA;(2)整合各分DFA,构造总DFA;(3)设计词法分析器算法;(4)根据DFA实现单词识别程序;(5)保存词法分析结果到文件。

输入:(1)输入为数学表达式,其中可能含有空格;(2)运算符包括+,-,*,/,(,)。

(3)运算数包括自然数和变量;(4)变量以下划线或字母开头,其后可以跟字母、下划线或数字。

输出:输出到文本文件。

每个单词输出为二元组(单词类别,单词值)。

单词类别编码见下表:编码 0 1 2例1:表达式xy-(x-100)/2的输出2,xy 0,- 0,( 2,x 0,- 1,100 0,) 0,/ 1,2第-1-页类别说明算符常量(自然数)变量《编译原理》课程实验实验1例2:表达式2x * (_x2 �C y)的输出1,2 2,x 0,* 0,( 2,_x2 0,- 2,y 0,)注意: 2x识别为两个单词2和x,虽然2x在语法上不合法(中间需要一个运算符),但在词法分析时不能发现这个错误。

例3:表达式x y * 012注意:该表达式x和y之间有一个空格,该词法分析程序的预处理程序简单的将空格全部去掉,因此与表达式xy*012的输出相同。

2,xy 0,* 1,0122.分DFA 2.1 自然数 2.2 标识符 2.3 算符3.合DFA说明:(1)状态0为初态。

(2)状态4为程序正常出口,说明识别出一个单词,单词类别由前一个状态决定。

(3)状态5为出错状态。

(4)为进一步确定下一步要做什么,需要向前“假读”一个单词。

状态2、3的假读是必须的,状态1是为了程序上的统一进行假读。

4.数据结构说明 4.1 单词结点单词序列采用链表存储,每个结点表示一个单词,用如下结构表示:第-2-页《编译原理》课程实验实验1struct WORDNODE {unsigned short byType; // 单词类别 char Value[MAX_DATA_LEN]; // 值WORDNODE *pNext; // 下一结点 };单词链表结构在WordAnalysis()函数中创建,并由此函数返回头结点指针;在main()函数中销毁。

实验1 词法分析

实验1      词法分析

实验1 词法分析一、目的与要求1)目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。

2)要求(1)掌握词法分析的实现方法。

(2)上机调试编出的词法分析程序。

(3)源程序可以从键盘输入也可以事先存在文件中(4)将源程序中的各个单词读出后可以显示在屏幕中也可以存在文件中(包括单词的类别)3)题目用C/C++ 语言编写以下C/C++ 子集的词法分析程序。

附C/C++ 语言子集的语法定义●〈C/C++ 子集程序〉→〈变量说明〉〈分程序〉●〈变量说明〉→〈空〉|VAR〈变量表〉:INTEGER;●〈变量表〉→〈变量〉|〈变量〉,〈变量表〉●〈变量〉→〈标识符〉●〈分程序〉→BEGIN〈语句组〉END●〈语句组〉→〈语句〉|〈语句〉;〈语句组〉●〈语句〉→〈赋值语句〉|〈条件语句〉|〈WHILE语句〉|〈分程序〉●〈赋值语句〉→〈变量〉:=〈算术表达式〉●〈条件语句〉→IF〈布尔表达式〉THEN〈语句〉ELSE〈语句〉●〈WHILE语句〉→WHILE〈布尔表达式〉DO〈语句〉●〈算术表达式〉→〈项〉|〈算术表达式〉+〈项〉|〈算术表达式〉-〈项〉●〈项〉→〈初等量〉|〈项〉*〈初等量〉|〈项〉/〈初等量〉●〈初等量〉→〈无符号数〉|〈变量〉|(〈算术表达式〉)●〈关系表达式〉→〈算术表达式〉〈关系运算符〉〈算术表达式〉●〈标识符〉→〈字母〉|〈标识符〉〈字母〉|〈标识符〉〈数字〉●〈无符号数〉→〈数字〉|〈无符号数〉〈数字〉●〈关系运算符〉→〈|〈=| =| 〉=| 〉|〈〉●〈字母〉→A│B│C│D│E│F│G│H│I│J│K│L│M│N│O│P│Q│R│S│T││U│V│W│X│Y│Z●〈数字〉→1│2│3│4│5│6│7│8│9│0输入:VAR X1:INTEGER; WHILE X1 DO 1X VAR X=100输出:VAR A1X1 A31X 错误单词分类:1关键字2标识符3运算符4数字5界符【代码如下】#include <iostream>#include <string.h>#include <stdio.h>#include <fstream>#include <ctype.h>using namespace std;charKey[9][10]={"VAR","INTEGER","BEGIN","END","DO","WHILE","IF ","THEN","ELSE"};//关键字char JF[5][3]={":",";",",","(",")"};//界符char GX[6][3]={"<","<=","=",">",">=","<>"};//关系运算符char YS[5][3]={"+","-","*","/",":="};int count;char word[1000];void check()//审查字符串{int i;for(i=0;i<9;i++){if(strcmp(word,Key[i])==0){cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"关键字"<<endl;return;}}for(i=0;i<5;i++){if(strcmp(word,JF[i])==0){cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"界符"<<endl;return;}}for(i=0;i<6;i++){if(strcmp(word,GX[i])==0){cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"关系运算符"<<endl;return ;}}for(i=0;i<5;i++){if(strcmp(word,YS[i])==0){cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"运算符"<<endl;return ;}}if(isupper(word[0])){for(i=1;word[i];i++){if(isupper(word[i]) || isdigit(word[i]))continue;else{cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"非法字符"<<endl;return ;}}cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"标识符"<<endl;return ;}else if(isdigit(word[0])){for(i=1;word[i];i++){if(isdigit(word[i]))continue;else{cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"非法字符"<<endl;return ;}}cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"无符号数"<<endl;return ;}cout<<count<<'\t'<<"字符串\t"<<word<<'\t'<<"非法字符"<<endl;return ;}int main(){bool val=true;char ch;int p=0;count=1;cout<<"**************************************** ****"<<endl;cout<<"序号"<<'\t'<<"字符串"<<""<<'\t'<<'\t'<<"类别"<<endl;cout<<"**************************************** ****"<<endl;while(true){if(val)ch=getchar();elseval=true;if(ch==' '|| ch=='\n' || ch=='\t'){if(p!=0 ){word[p]=0;p=0;check();count++;}}else if(ch==':' || ch==',' || ch==';' || ch=='(' || ch==')') {if(p!=0){word[p]=0;check();count++;p=0;}word[p++]=ch;ch=getchar();if(word[0]==':' && ch=='='){word[p++]=ch;word[p]=0;check();count++;p=0;}else{word[p]=0;check();count++;p=0;val=false;}}else if(ch=='+' || ch=='-' || ch=='*' || ch=='/') {if(p!=0){word[p]=0;check();count++;p=0;}word[p++]=ch;word[p]=0;check();count++;p=0;}else if(ch=='>' || ch=='<' || ch=='=') {if(p!=0){word[p]=0;check();count++;p=0;}word[p++]=ch;if(ch!='='){ch=getchar();if(ch=='=' || (word[p-1]=='<'&&ch=='>')) {word[p++]=ch;word[p]=0;check();count++;p=0;}else{word[p]=0;check();count++;p=0;val=false;}}else{word[p]=0;check();count++;p=0;}}else{word[p++]=ch;}}return 0;}【输入数据如下】VAR A,B,C,D:INTEGE; A=B;A+B;A+B=C;A:=B;A>=C;A B ASD A%D BEGINIF A=BELSE a=12343;WHILE A>=0DO A=B;1*2:=3;FI THEN ELSE#@$@#$ sdfsd sdf s sw A+(A=B+(N+M))IF A<>BELSE A=B-1;-2342+2341-1-1-1-1+=:=11110; 0001,0002;。

实验一(词法分析)

实验一(词法分析)

实验一词法分析一.实验目的1、学会针对DFA转换图实现相应的高级语言源程序。

2、深刻领会状态转换图的含义,逐步理解有限自动机。

3、掌握手工生成词法分析器的方法,了解词法分析器的内部工作原理。

二.实验内容计算机程序设计语言的编译程序的词法分析部分实现。

给出算法的流程图及有穷状态自动机的模型(可以用矩阵或者状态图表示)从左到右扫描每行该语言源程序的符号,拼成单词,换成统一的内部表示(token)送给语法分析程序。

为了简化程序的编写,有具体的要求如下:(1)数仅仅是整数。

(2)空白符仅仅是空格、回车符、制表符。

(3)代码是自由格式。

(4)注释应放在花括号之内,并且不允许嵌套三.实验要求要求实现编译器的以下功能:(1)按规则拼单词,并转换成二元式形式(2)删除注释行(3)删除空白符 (空格、回车符、制表符)(4)列表打印源程序,按照源程序的行打印,在每行的前面加上行号,并且打印出每行包含的记号的二元形式(5)发现并定位错误词法分析进行具体的要求:(1)记号的二元式形式中种类采用枚举方法定义;其中保留字和特殊字符是每个都一个种类,标示符自己是一类,数字是一类;单词的属性就是表示的字符串值。

(2)词法分析程序当识别一个单词完毕,采用返回值的形式返回符号的种类,同时采用程序变量的形式提供当前识别出记号的属性值。

(3)标示符和保留字的词法构成相同,为了更好的实现,把语言的保留字建立一个表格存储,这样可以把保留字的识别放在标示符之后,用识别出的标示符对比该表格,如果存在该表格中则是保留字,否则是一般标示符。

(选做)四.实验结果(1)测试用例(2)实验结果的屏幕截图五.实验总结。

实验一:词法分析JN

实验一:词法分析JN

实验一:词法分析一、实验目的给出PL/0文法规范,要求编写PL/0语言的词法分析程序。

二、实验准备微机CPU主频1.3G以上,128M内存,安装好C语言,PASCAL语言,或C++。

三、实验时间6学时四、实验内容已给PL/0语言文法,输出单词(关键字、专用符号以及其它标记)。

二.实验内容1、格式输入:源程序文件。

输出:关键字、专用符号以及其它标记。

2、编译对象:包含如下基本内容 1)变量说其它标记: 明语句 2)赋值语句 3)条件转移语句 4)表达式(算术表达式和逻辑表达式) 5)循环语句 6)过程调用语句3、实现过程本次实验所用的语言为标准C,以下同。

本功能实现的主函数为getToken函数。

通过从文件中读取字符到缓冲区中并由C语言字符的状态转换图流程判断返回一个字符(Token)。

分析出来的Token主要分为关键字,专用符号,标记符号。

本实验实现的C语言的基本词法如下:关键字: els if int return void while专用符号: + - * / < >= == != = ; , ( ) [ ] { } /* */其它标记: id numID = letter letter*NUM = digit digit*letter = a|b|...|z|A|B|...|Z|ditit= 0|1|...|9通过在C语言中定义一个枚举类型来识别这些符号:PL/0语言的EBNF表示<常量定义>::=<标识符>=<无符号整数>;<标识符>::=<字母>={<字母>|<数字>};<加法运算符>::=+|-<乘法运算符>::=*|/<关系运算符>::==|#|<|<=|>|>=<字母>::=a|b|…|X|Y|Z<数字>::=0|1|2|…|8|94、主体结构的说明在这里说明部分告诉我们使用的LETTER,DIGIT, IDENT(标识符,通常定义为字母开头的字母数字串)和STR(字符串常量,通常定义为双引号括起来的一串字符)是什么意思.这部分也可以包含一些初始化代码.例如用#include来使用标准的头文件和前向说明(forward ,references).这些代码应该再标记"%{"和"%}"之间;规则部分&gt;可以包括任何你想用来分析的代码;我们这里包括了忽略所有注释中字符的功能,传送ID名称和字符串常量内容到主调函数和main函数的功能.5、实现原理程序中先判断这个句语句中每个单元为关键字、常数、运算符、界符,对与不同的单词符号给出不同编码形式的编码,用以区分之。

词法分析实验报告(实验一)

词法分析实验报告(实验一)

词法分析实验报告(鲍小伟20032320)一.实验目的:通过设计、编程、调试出一个具体词法分析程序,加深对词法分析原理的理解,掌握其设计方法。

二.实验内容:用C/C++实现对PASCAL的子集程序设计语言的词法识别程序。

三.实验要求与原理:(1)实验要求:将该语言的源程序,即相应字符流转换成内部表示,并对标识符填写相应的符号表供编译程序以后各阶段使用,输出的单词符号格式为二元组(单词种别,单词在标识符表中的地址),标识符表格式有“序号”和“标识符本身的值”两项。

写出设计报告,内容为:状态转换图、单词符号及内部表示、符号表、出错处理、编程方法等。

(2)实验原理:状态转换图:空白8923单词符号及内部表示:标志符表和常数表:void getchar();//将下一输入字符读到ch中,指针后移一字符位置void getbc();//保证ch是一个非空白字符void concat();//将ch连接到字符串stroken的末尾void retract();//置ch为空白字符,指针前移一字符位置int isdigit();//判断是否整数int isletter();//首字母的判断int reserve();//对stroken进行关键字表的查找,返回其编码值int insertid();//将stroken中的标识符插入符号表,返回在符号表中的位置int insertconst();//将stroken中的常数插入常数表,返回在常数表中的位置四.主要源代码:Scanner::Scanner(char str[], int n) //构造函数{strcpy(buffer, str);length = n;i = j = 0;}int Scanner::isdigit()//判断是否整数{if(ch>='0' && ch<='9')return 1;elsereturn 0;}int Scanner::isletter()//首字母的判断{if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))return 1;elsereturn 0;}void Scanner::getchar() //将下一输入字符读到ch中,指针后移一字符位置{ch = buffer[i];i++;}void Scanner::getbc() //保证ch是一个非空白字符{while(ch == ' ')getchar();}void Scanner::concat() //将ch连接到字符串stroken的末尾{strtoken[j] = ch;j++;}void Scanner::retract() //置ch为空白字符,指针前移一字符位置{ch = ' ';i--;}int Scanner::reserve() //对stroken进行关键字表的查找,返回其编码值{int i, flag = 0;for(i=0; i<15; i++){if( strncmp(reservechar[i],strupr(strtoken), j) == 0 ){flag = 1;break;}}if(flag == 1) return i+1;else return 0;}int Scanner::insertid() //将stroken中的标识符插入符号表,返回在符号表中的位置{for(int a = 0; a < m; a++)for(int b = 0; b < x[a]; b++)if( strncmp(&id[a][0], strtoken, j) == 0 ){return m+1;break;}for(a = 0; a < j; a++)id[m][a] = strtoken[a];x[m] = j;m++;return m;}int Scanner::insertconst() //将stroken中的常数插入常数表,返回在常数表中的位置{for(int i = 0; i < j; i++)cst[n][i] = strtoken[i];y[n] = j;n++;return n;}void Scanner::scan(){while(i < length){j = 0;int code, value;strcpy(strtoken, " "); //置strtoken为空串getchar();getbc();if(isletter()) //如果打头的是字母{while(isletter() || isdigit()){concat();getchar();}retract();code = reserve();if(code == 0) //如果扫描到的是标识符{value = insertid();cout<<"<34,"<<value<<">"<<'\n';}else cout<<"<"<<code<<",*>"<<'\n'; //如果扫描到的是关键字}else if(isdigit()) //如果打头的是数字{while(isdigit()){concat();getchar();}retract();value = insertconst();cout<<"<33,"<<value<<">"<<'\n';}else if(ch == '+')cout<<"<16,*>"<<'\n';else if(ch == '-')cout<<"<17,*>"<<'\n';else if(ch == '*')cout<<"<18,*>"<<'\n';else if(ch == '/')cout<<"<19,*>"<<'\n';else if(ch == '=')cout<<"<20,*>"<<'\n';else if(ch == '<'){getchar();if(ch == '>')cout<<"<21,*>"<<'\n';else if(ch == '=')cout<<"<23,*>"<<'\n';else{retract();cout<<"<22,*>"<<'\n';}}else if(ch == '>'){getchar();if(ch == '=')cout<<"<25,*>"<<'\n';else{retract();cout<<"<24,*>"<<'\n';}}else if(ch == '.')cout<<"<26,*>"<<'\n';else if(ch == ',')cout<<"<27,*>"<<'\n';else if(ch == ';')cout<<"<28,*>"<<'\n';else if(ch == ':'){getchar();if(ch == '=')cout<<"<30,*>"<<'\n';else{retract();cout<<"<29,*>"<<'\n';}}else if(ch == '(')cout<<"<31,*>"<<'\n';else if(ch == ')')cout<<"<32,*>"<<'\n';else if(ch == '{'){while(ch != '}')getchar();}else cout<<"出错!"<<'\n';}}void main(void){fstream file;file.open("F:/20032320/20032320.txt", ios::in||ios::nocreate); //以只读方式打开file.unsetf(ios::skipws); //不跳过文本中的空格char buffer[100]; //缓冲区定义cout<<"扫描结果如下所示"<<'\n';while(file.getline(buffer, 100)){Scanner SS(buffer, strlen(buffer));SS.scan();}cout<<"标识符表如下:\n"<<"编号\t"<<"值\n";for(int i=0; i<m; i++){cout<<i+1<<'\t';for(int j=0; j<x[i]; j++)cout<<id[i][j];cout<<'\n';}cout<<"常数表如下:\n"<<"编号\t"<<"值\n";for(i=0; i<n; i++){cout<<i+1<<'\t';for(int j=0; j<y[i]; j++)cout<<cst[i][j];cout<<'\n';}}五.运行结果:程序的运行结果如下图所示:。

编译原理实验报告 词法分析

编译原理实验报告 词法分析

编译原理实验一·词法分析一、实验目的通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。

同时增强编写和调试程序的能力。

二、实验内容及要求对某特定语言A ,构造其词法规则。

该语言的单词符号包括:保留字(见左下表)、标识符(字母大小写不敏感)、整型常数、界符及运算符(见右下表) 。

功能要求如下所示:·按单词符号出现的顺序,返回二元组序列,并输出。

·出现的标识符存放在标识符表,整型常数存放在常数表,并输出这两个表格。

·如果出现词法错误,报出:错误类型,位置(行,列)。

·处理段注释(/* */),行注释(//)。

·有段注释时仍可以正确指出词法错误位置(行,列)。

三、实验过程1、词法形式化描述使用正则文法进行描述,则可以得到如下的正规式:其中ID表示标识符,NUM表示整型常量,RES表示保留字,DEL表示界符,OPR表示运算符。

A→(ID | NUM | RES | DEL | OPR) *ID→letter(letter | didit)*NUM→digit digit*letter→a | …| z | A | …| Zdigit→0 | …| 9RES→program | begin | end | var | int | and | or | not | if | then | else | while | doDEL→( | ) | . | ; | ,OPR→+ | * | := | > | < | = | >= | <= | <>如果关键字、标识符和常数之间没有确定的算符或界符作间隔,则至少用一个空格作间隔。

空格由空白、制表符和换行符组成。

2、单词种别定义;3、状态转换图;语言A的词法分析的状态转换图如下所示:空格符,制表符或回车符字母或数字4、运行环境介绍;本次实验采用win-tc进行代码的编写和编译及运行程序的运行环境为windows5、关键算法的流程图及文字解释;程序中用到的函数列表:变量ch储存当前最新读进的字符的地址strToken存放当前字符串voidmain() //主函数struct binary *lexicalAnalyze(); //词法分析的主函数,返回一个二元组的指针void GetBC(); //检查ch指向的字符是否为空格、制表或回车符,如果是则调用GetChar()直至不是上述字符void GetChar(); //ch前移一个地址单元int ConCat(); //将ch指向的字符连接到strToken之后int isLetter(); //判断ch指向的字符是否字母int isDigit(); //判断ch指向的字符是否数字int insertId(); //向标识符表中插入当前strToken的字符串int insertConst(); //将strToken的常数插入常数表中int Reserved(); //检测当前strToken中的字符串是否保留字,若是,则返回编码,否则返回0int isId(); //检测当前strToken中的字符串是否在标识符表中已存在,若是,则返回其编号,否则返回0int isConst(); //检测当前strToken中的字符串是否在常数表中已存在,若是,则返回其编号,否则返回0void errProc(int errType); //出错处理过程,errType是错误类型,将错误信息加入错误表中main()函数的流程图如下:lexicalAnalyze()函数的流程图如下所示:Reserved()、isId()和isConst()函数均采用了对链表的遍历算法,errProc()函数通过识别不同的错误编号,向错误链表中添加相应的错误信息。

实验一词法分析

实验一词法分析
cout<<"输出该非标示符:";
for (int i=0;i<50;i++)
{
cout<<a[i];
}
cout<<endl;
cout<<"------------字符串判断完毕------------"<<endl;
}
system("pause");
return 0;
}
Vc6.0新建空工程+源文件
{
b[k]=a[t+1]; //存放是标识符的字符
k++;
}
else if((a[t+1]>='0')&&(a[t+1]<='9')) //识别是非标识符的字符
{
c[m]=a[t+1]; //存放是单个数字的字符
m++;
}
else{
e[p]=a[t+1]; //存放是非标识符的字符
p++;
}
}
cout<<"--------------判断结果----------------"<<endl;
char a[50]={0}; //存放字符串
char b[50]={0}; //存放标志符
char d[50]={0}; //存放非标识符
cout<<"请输入字符串(以$结束):"<<endl;
for(int i=0;i<50;i++)

实验一词法分析(单词识别)

实验一词法分析(单词识别)

实验一:词法分析一、实验目的:通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。

并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。

编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。

并依次输出各个单词的内部编码及单词符号自身值。

(遇到错误时可显示“Error”,然后跳过错误部分继续显示)二、实验预习提示1、词法分析器的功能和输出格式词法分析器的功能是输入源程序,输出单词符号。

词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。

本实验中,采用的是一类符号一种别码的方式。

2、单词的BNF表示<标识符>-> <字母><字母数字串><字母数字串>-><字母><字母数字串>|<数字><字母数字串>|<下划线><字母数字串>|ε<无符号整数>-> <数字><数字串><数字串>-> <数字><数字串> |ε<加法运算符>-> +<减法运算符>-> -<大于关系运算符>-> ><大于等于关系运算符>-> >=3、“超前搜索”方法词法分析时,常常会用到超前搜索方法。

如当前待分析字符串为“a>+”,当前字符为’>’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?显然,只有知道下一个字符是什么才能下结论。

于是分析器读入下一个字符’+’,这时可知应将’>’解释为大于运算符。

但此时,超前读了一个字符’+’,所以要回退一个字符,词法分析器才能正常运行。

在分析标识符,无符号整数等时也有类似情况。

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

编译原理实验一词法分析1.实验目的通过实验掌握词法分析的理论、原理和方法,为语法分析做准备。

2.实验内容:a)十六进制数识别器:规定是:必须以十六进制数字打头,以H结尾,十六进制数中允许使用的数字为0-9,字母为A,B,C,D,E, F(分别表示0~15)。

试设计一个DFA,使它能识别无符号的十六进制整数,并编制相应的识别程序。

输入:学生自行确定符号串的输入形式,如键盘输入、文本文件、字符数组等。

输出:标识出规范的符号串与不合规范的符号串。

b)词法分析:设计、编制、调试一个识别一个Little语言单词的词法分析程序(见附录1)。

输入:学生自行确定符号串的输入形式,如键盘输入、文本文件、字符数组等。

输出:二元组。

3.实验要求:(1)上机前编写完整的实验报告,报告中要体现分析→设计→实现等几个过程;如无实验报告,则取消本次上机资格,实验成绩以0分记。

(2)严禁相互抄袭,否则实验成绩以0分记;(3)有完整的源代码,源码有规范的注释,无明显的语法错误;4.实验步骤(1)分析与设计a、文法:该语言的十六进制,如:0aH,77H,7BH等由以数字打头及以H结尾;该语言的标识符,如:Num,a3,go等由A到Z(or a到z)和0至9所组成;该语言的无符号的十进制,如:8,90,123等由0到9之间的任意数字组成。

由以上可得出该语言的文法可表示如下:G(S) = (VN,VT,P,S)其中VN={S,X’,Y’,Z’,M’,W’,α,β,γ,μ,υ,ω}VT= {0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}α= 0|1| 2|3|4|5|6|7|8|9β= a|b|c|d|e|f|A|B|C|D|E|Fγ=g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|G|H|I|G|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|ZS →X’|Y’|Z’X’→υ|υM’M’→ω|ωM’υ→β|γω→α|β|γY’→α|αY’Z’→αH|αW’HW’→μ|μW’μ→α|β可见,上式方法中,X’表示出了语言的标识符,而Y’表示出了语言的无符号的十进制,Z’表示出了语言中的十六进制。

∵上式G(S)文法中,各式右边只有单个的终结符号∴显然,以上文法G(S)已是正规文法。

(2)正规文法转成正规式:具体步骤如下:∵ M’→ω|ωM’可表示为M’→ω*ωW’→μ|μW’可表示为W’→μ*μZ’→α|αZ’可表示为Z’→α*α∴转换成正规表达式为:S=υ| υω*ω|αH | αμ*μH |α*α代入可得:S= (β|γ) | (β|γ) (α|β|γ)*(α|β|γ) |αH | α(α|β)* (α|β)H |α*α(3)正规式转成NFA(分裂法)初始的NFA图下所示:图1 初始NFA图经过替换规则替换后得到的最终NFA图如下所示:图2 最终的NFA图(4)NFA转成DFA及DFA最小化(造表法)对应以上的NFA图,我们可用造表法来表示如下:显然,由图可看出,状态2与状态5等价,而状态1与状态3等价,这里省去状态3和状态5,并将所以指向状态3的状态都指向状态1,指向状态5的都指向状态2。

由此可画出最小化的DFA图如下:图3 最小化的DFA图可见,终结状态1表示出了无符号的十进制,终结状态2表示出了标识符,状态6表示出了十六进制的整数。

b、单词的BNF表示<标识符>-> <字母><字母数字串><字母数字串>-><字母><字母数字串>|<数字><字母数字串>|<下划线><字母数字串>|ε<无符号整数>-> <数字><数字串><数字串>-> <数字><数字串> |ε<加法运算符>-> +<减法运算符>-> -<大于关系运算符>-> ><大于等于关系运算符>-> >=由此可知,需将单词分为五种:关键字1 标识符2 常数3 运算符4 分隔符5(2)编码实现a、#include <stdio.h>main(int argc,char *argv[]){int i,j,state,ERROR=-1;/* state控制状态的转移1表示0~9数字,2表示字母,4表示a~f,6表示H,0为未输入状态* ERROR=-1表示未输入任何字符串=1表示输入出错*/char c; /* 暂时存放所取得的一个字符*/char *string[]={"","Unsigned Integer","Identifier","","","","Hex"};/*输出结果时用*/ for(i=1;i<argc;i++){state=0; /* 初始态为0 */ERROR=0; /* 控制是否为可识别词or非法字符*/for(j=0;(c=argv[i][j])!='\0';j++){switch(state){case 0:if(c>='0'&&c<='9')state=1;else if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))state=2;else ERROR=1;break;/* ERROR=1,表示当前字符c为非法字符。

* 即此时无状态可转向。

*/case 1:if(c>='0'&&c<='9')state=1;else if((c>='a'&&c<='f')||(c>='A'&&c<='F'))state=4;else if (c=='H')state=6;elseERROR=1;break;case 2:if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||(c>='0'&&c<='9'))state=2;elseERROR=1;break;case 4:if((c>='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F'))state=4;else if(c=='H')state=6;elseERROR=1;break;case 6:ERROR=1;break;}/*end switch*/if(ERROR==1)break; /* 退出内for的循环,完成一个词的分析。

*/ }/*end inside-for*/if(ERROR==1)printf("%-15s is a un-identify word!\n",argv[i]);else if(ERROR==0)printf("%-15s is a %s\n",argv[i],string[state]);}/*end outside-for*//*未输入任何字符串时(除文件名外)*/if(ERROR==-1) printf("You input nothing!\n");exit(0); /*正常退出程序*/}/*end main*/b、#include<string.h>#include<stdio.h>#include<stdlib.h>#include<ctype.h>//定义关键字char *table[7]={"continue","main","int","if","then","else","return"},TOKEN[20],ch; bool zimu(char ch)//判断是否为字母{if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return true;elsereturn false;}//判断是否为数字bool shuzi(char ch){if(ch>='0'&&ch<='9')return true;elsereturn false;}int lookup(char *TOKEN) //关键字匹配函数,查询所述程序中的关键字{int m,i;for(i=0;i<6;i++){if((m=strcmp(TOKEN,table[i]))==0)return 1;}return 0;}void out(int c,char *TOKEN) //输出函数{ printf("(%d,%s)\n",c,TOKEN);}void scanner(FILE *fp) //扫描函数{char TOKEN[20]={'\0'};char ch;int i;ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符if(zimu(ch) //判断该字符是否是字母,若ch指的是字母,返回非0,否则返回0 { TOKEN[0]=ch;ch=fgetc(fp); //fgetc(fp)从数据流中区下一个字符i=1;while(shuzi(ch)|| zimu(ch)) //判断该字符是否是字母或数字{TOKEN[i]=ch;ch=fgetc(fp);i++;}fseek(fp,-1,1);if(lookup(TOKEN)) //判断是关键字还是普通的标识符out(1,TOKEN);elseout(2,TOKEN);}else if(shuzi(ch)){TOKEN[0]=ch;ch=fgetc(fp); //fgetc(fp)从数据流中区下一个字符i=1;while(shuzi(ch)) //判断该字符是否是字母或数字{TOKEN[i]=ch;ch=fgetc(fp);i++;}fseek(fp,-1,1);out(3,TOKEN);}//判断运算符并输出else if(ch=='+'){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='-'){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='*'){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='/'){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='='){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='>'){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='<'){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='>='){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='<='){ TOKEN[0]=ch; out(4,TOKEN); }else if(ch=='!='){ TOKEN[0]=ch; out(4,TOKEN); }//判断分隔符并输出else if(ch==','){ TOKEN[0]=ch; out(5,TOKEN); }else if(ch==';'){ TOKEN[0]=ch; out(5,TOKEN); }else if(ch=='{'){ TOKEN[0]=ch; out(5,TOKEN); }else if(ch=='}'){ TOKEN[0]=ch; out(5,TOKEN); }else if(ch=='('){ TOKEN[0]=ch; out(5,TOKEN); }else if(ch==')'){ TOKEN[0]=ch; out(5,TOKEN); }}main(){FILE *fp;//读取文件内容,并返回文件指针,该指针指向文件的第一个字符if((fp=fopen("E:\\222.txt","r"))==NULL){fprintf(stderr,"error opening.\n");exit(1);}do{ch=fgetc(fp);if(ch=='#') //文件以#结尾,作为扫描结束条件break;if(ch==' ') //如果是空格,自动跳到下个字符scanner(fp);else{fseek(fp,-1,1); //如果不是空格,则回退一个字符并扫描scanner(fp);}}while(ch!='#');return 0;}(3)系统调试a、b、5.实验总结通过此次实验,使我意识到在做实验之前一定要认真复习课本内容和老师的要求以此来确定该实验要我们实现的是什么,怎么实现,每一步的步骤都要按照流程图认真的去完成,做实验不能有半点马虎。

相关文档
最新文档