实验一 词法分析
实验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+单词符号输出形式⇒构造词法分析程序。
词法分析报告设计实验报告材料(附代码)
实验一词法分析设计实验学时: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 词法分析实验报告
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)关键字: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,”}”)七、实验报告要求给出单词识别的状态转换图;带有注释(简单说明)的源程序。
编译原理-实验报告1-词法分析
计算机硬件实验室实验报告姓名学号班级词法分析成绩设备名称及软件环境一、实验目的:通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error”,然后跳过错误部分继续显示)二、实验要求:识别保留字:if、int、for、while、do、return、break、continue,等C语言的保留字;单词种别码为1。
其他的都识别为标识符;单词种别码为2。
常数为无符号整形数;单词种别码为3。
运算符包括:+、-、*、/、=、>、<、>=、<=、!=;单词种别码为4。
分隔符包括:,、;、{、}、(、)、[、];单词种别码为5。
三、实验过程:根据题目要求,初步完成程序过程的设计,模块的划分、变量类型分配。
#inlclude<stdio.h>int main(){int d,a,c;a=10;c=a+b;printf("%d%d",a,b);;return 0;}用以上定义的C语言子集的源程序作为词法分析程序的输入数据。
在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。
经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
0.定义部分:定义常量、变量、数据结构。
1.初始化:从文件将源程序全部输入到字符缓冲区中。
2.取单词前:去掉多余空白。
3.取单词:利用实验一的成果读出单词的每一个字符,组成单词,分析类型。
词法分析设计实验报告(附代码)
实验一词法分析设计实验学时: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) 其他单词是标识符(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>using namespace std;char prog[80],token[8];char ch;int syn,p,m=0,n,sum=0; //p是缓冲区prog的指针,m是token的指针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++];//执行语句1;if((ch>='a')&&(ch<='z')||(ch>='A')&&(ch<='Z'))//判断是否是字母字符{ m=0;while((ch>='A')&&(ch<='Z')||(ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){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;}}elseif(ch>='0'&&ch<='9'){ sum=0;while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=11; //执行语句2;}elseswitch(ch){case'>':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=24;token[m++]=ch;}else {syn=23;p--;}break;case'<': m=0;token[m++]=ch; //补充程序;ch=prog[p++];if(ch=='='){syn=22;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=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;default:syn=-1;}}void main(){p=0;cout<<"\n please input string: \n";do {ch=getchar();prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){ case 11: cout<<"(11,"<<sum<<")"; break;case -1: cout<<"error!"; break;default: cout<<"("<<syn<<","<<token<<")";}}while (syn!=0);}四、结果验证(1) 给定源程序begin x:=9;if x>0 then x:=2*x+1/3; end#输出结果。
[实验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.实验目的通过实验掌握词法分析的理论、原理和方法,为语法分析做准备。
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、学会针对DFA转换图实现相应的高级语言源程序。
2、深刻领会状态转换图的含义,逐步理解有限自动机。
3、掌握手工生成词法分析器的方法,了解词法分析器的内部工作原理。
二.实验内容计算机程序设计语言的编译程序的词法分析部分实现。
给出算法的流程图及有穷状态自动机的模型(可以用矩阵或者状态图表示)从左到右扫描每行该语言源程序的符号,拼成单词,换成统一的内部表示(token)送给语法分析程序。
为了简化程序的编写,有具体的要求如下:(1)数仅仅是整数。
(2)空白符仅仅是空格、回车符、制表符。
(3)代码是自由格式。
(4)注释应放在花括号之内,并且不允许嵌套三.实验要求要求实现编译器的以下功能:(1)按规则拼单词,并转换成二元式形式(2)删除注释行(3)删除空白符 (空格、回车符、制表符)(4)列表打印源程序,按照源程序的行打印,在每行的前面加上行号,并且打印出每行包含的记号的二元形式(5)发现并定位错误词法分析进行具体的要求:(1)记号的二元式形式中种类采用枚举方法定义;其中保留字和特殊字符是每个都一个种类,标示符自己是一类,数字是一类;单词的属性就是表示的字符串值。
(2)词法分析程序当识别一个单词完毕,采用返回值的形式返回符号的种类,同时采用程序变量的形式提供当前识别出记号的属性值。
(3)标示符和保留字的词法构成相同,为了更好的实现,把语言的保留字建立一个表格存储,这样可以把保留字的识别放在标示符之后,用识别出的标示符对比该表格,如果存在该表格中则是保留字,否则是一般标示符。
(选做)四.实验结果(1)测试用例(2)实验结果的屏幕截图五.实验总结。
实验一:词法分析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).这些代码应该再标记"%{"和"%}"之间;规则部分>可以包括任何你想用来分析的代码;我们这里包括了忽略所有注释中字符的功能,传送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';}}五.运行结果:程序的运行结果如下图所示:。
词法分析~实验报告
词法分析~实验报告实验⼀、词法分析实验专业商业软件3班姓名陈笑璞学号 201506110218⼀、实验⽬的(1)编制⼀个词法分析程序(2)词法分析是编译的第⼀个阶段,主要任务是从左⾄右逐个字符地对源程序进⾏扫描,产⽣⼀个个单词序列,⽤于语法分析。
(3)通过词法分析的练习,能够进⼀步了解编译原理。
(4)通过了解词法分析程序的设计原则、单词的描述技术、识别机制及词法分析程序的⾃动构造原理。
⼆、实验内容和要求(1)输⼊:源程序字符串(2)输出:⼆元组(种别,单词符号本⾝)。
三、实验⽅法、步骤及结果测试实验⽅法、步骤:(1)对字符串表⽰的源程序(2)从左到右进⾏扫描和分解(3)根据词法规则(4)识别出⼀个⼀个具有独⽴意义的单词符号(5)以供语法分析之⽤(6)发现词法错误,则返回出错信息2、原理分析: 我的设计思路是利⽤链队列(好处:先进先出且不浪费存储空间)进⾏存储⽤户输⼊字符串,以回车键结束(其中必须以⾮数字结尾,否则程序出错)(这是我在后来的编程⾥遇到的问题,我知道问题出在哪⾥,但我现在还解决不了,因为我是通过申请⼦针域来存储,所以我是利⽤p->next来作为判断结束条件,如果以数字结束,那p->next指向未知领域,程序出错,同时这也是很危险的),然后我是利⽤出队列来判断,如果是字母存进数组⾥,直到下⼀个字符不是字母,调⽤函数判断数组的字符串,利⽤strcmp来判断,输出数组,再清空数组;void Print(char str[])//调⽤函数来判断关键字与标识符并输出{int i=0;if(strcmp(str,"begin")==0)printf("(1,'%s')\n",str);else if(strcmp(str,"if")==0)printf("(2,'%s')\n",str);else if(strcmp(str,"then")==0)printf("(3,'%s')\n",str);else if(strcmp(str,"while")==0)printf("(4,'%s')\n",str);else if(strcmp(str,"do")==0)printf("(5,'%s')\n",str);else if(strcmp(str,"end")==0)printf("(6,'%s')\n",str);else{if(str[0]=='\0')return;printf("(10,'%s')\n",str);}memset(str,0,N);//清空数组str⾥的所有元素}结果测试:四、实验总结说实话,通过这次的编译原理词法分析的实验,我遇到了不少问题,也学到了不少的东西,因为这次实验我是想⽤我⾃⼰的想法来编写程序,我是⽤链队列来存储字符串的,也许⽤数组来存储字符串会简单点,但我不想,我还是想利⽤链队列来存储字符串,这样可以节约存储空间,还可以利⽤队列先进先出的特点,不好就是利⽤队列不够灵活,每次都要出栈判断、存储,释放p的⼦针域;虽然在编写过程中,遇到不少问题,遇到⼀个,就想办法解决⼀个,通过问朋友⽼师等,也通过发朋友圈问,还通过发博客来问⼤神们,这种途径是最有效的,也是最好的;所以每次就差⼀点就做好了,⼜会遇到⼀个新的问题,就要想办法去解决它,如今除了字符串是以数字结尾会出现问题外(暂时没找到好的⽅法),其他问题已解决。
编译原理实验报告 词法分析
编译原理实验一·词法分析一、实验目的通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。
同时增强编写和调试程序的能力。
二、实验内容及要求对某特定语言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()函数通过识别不同的错误编号,向错误链表中添加相应的错误信息。
实验一词法分析
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、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验一词法分析一实验目的和要求通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error”,然后跳过错误部分继续显示)二实验内容1 功能描述1.1 词法分析器的功能和输出格式词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
本实验中,采用的是一类符号一种别码的方式。
如源程序为C语言。
输入如下一段:main(){int a,b,c=2;a = 10;b = a + 20;c = a + b/c;}#要求输出如右图。
1.2 单词的BNF表示<标识符>-> <字母><字母数字串><字母数字串>-><字母><字母数字串>|<数字><字母数字串>|<下划线><字母数字串>|ε<无符号整数>-> <数字><数字串><数字串>-> <数字><数字串> |ε<加法运算符>-> +<减法运算符>-> -<大于关系运算符>-> > (1,main)(5,()(5,))(5,{)(1,int)(2,a)(5,,)(2,b)(2,c)(4,=)(3, 2)(5,;)(2,a)(4,=)(3,10)(5,;)(2,b)(4,=)(2,a)(4,+)(3,20)(5,;)(2,c)(4,=)(2,a)(4,+)(2,b)(4,/)(2,c)(5,;)(5,})<大于等于关系运算符>-> >=由此可知,需将单词分为五种:关键字1 标识符2 常数3 运算符4 分隔符5printf a 0 + ,main b 1 _ ;int c 2 * (if student 3 / )then sum 4 = {else k 5 > }return m 6 < ….…. …. 7 >=8 <=9 !=1.3 “超前搜索”方法词法分析时,常常会用到超前搜索方法。
如当前待分析字符串为“a>+”,当前字符为’>’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?显然,只有知道下一个字符是什么才能下结论。
于是分析器读入下一个字符’+’,这时可知应将’>’解释为大于运算符。
但此时,超前读了一个字符’+’,所以要回退一个字符,词法分析器才能正常运行。
在分析标识符,无符号整数等时也有类似情况。
2 程序思路这里以开始定义的C语言子集的源程序作为词法分析程序的输入数据。
在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。
经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
0.定义部分:定义常量、变量、数据结构。
1.初始化:从文件将源程序全部输入到字符缓冲区中。
2.取单词前:去掉多余空白。
3.取单词后:去掉多余空白(可选,看着办)。
4.取单词:利用实验一的成果读出单词的每一个字符,组成单词,分析类型。
(关键是如何判断取单词结束?取到的单词是什么类型的单词?)5.显示结果。
3 部分函数说明1. int lookup(char *TOKEN) 关键字匹配函数,查询所述程序中的关键字2. void out(int c,char *TOKEN) 输出函数3. void scanner(FILE *fp) 扫描函数,扫描程序中的字符串并调用lookup函数检查是否是关键字,再调用out函数输出二元组4.fseek(fp,-1,1)回退一个字符5.zimu(ch)字母判断函数,若ch指的是字母,返回非0,否则返回06.shuzi(ch)数字判断函数,若ch指的是数字,返回非0,否则返回07.fgetc(fp)从数据流中区下一个字符8.fopen 文件打开函数,返回指向文件第一个字符的指针三实验过程记录及实验结果1 程序开始定义zimu(ch)和shuzi(ch)函数时,需要直接返回ch类型的值,不需要再定义变量,而我又重复定义了变量,所以程序出现错误。
2 判断单词是关键字、标识符、整型常量、分隔符还是运算符时,关系到“回退”的概念,如果没有这个函数则运算结果会出现错误,即没有完全显示内容。
如下图(a):图(a)图(b)3 实验结果如图(b)四实验总结通过此次实验,使我意识到在做实验之前一定要认真复习课本内容和老师的要求以此来确定该实验要我们实现的是什么,怎么实现,每一步的步骤都要按照流程图认真的去完成,做实验不能有半点马虎。
此外,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理的理解;实验核心的部分在于如何识别初各个单词的所属类别,实验前可先规划一下试验流程,这样编写起来比较方便容易。
这次的实验使我熟悉了构造词法分析程序的手工方式的相关原理,也锻炼了自己编写算法以及C语言的能力,虽然在试验过程中存在着很多的不足,但经过老师以及同学的指点再加上自己的努力都一一克服了,今后我也会经常通过自己编写此类的代码来提高自己的能力。
附录:源代码#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;}。