实编译原理验一词法分析程序.doc
华北水利水电学院 编译原理 实验报告一、实验目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解,深刻理解词法分析的整个过程,提高词法分析方法的实践能力。二、实验要求(1)从源程序文件中读取有效字符和并将其转换成二元组机内表示形式输出。(2)掌握词法分析的实现方法。(3)实验要求独立完成,不允许有抄袭现象。(4)实验完成后,要上交实验报告(包括源程序清单)。三、实验内容、主程序设计考虑:主程序的说明部分为各种表格和变量安排空间(关键字和特殊符号表)。id 和ci 数组分别存放标识符和常数;还有一些为造表填表设置的变量。主程序的工作部分建议设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。)词法分析过程考虑该过程取名为 lexical,它根据输入单词的第一个有效字符(有时还需读第二个字符),判断单词类,产生类号。对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组 id 中,将常数存入数组中 ci 中,并记录其在表中的位置。3)功能要求输出源程序对应的二元组;对错误单词能够报错,并提示出错误所在行;常量和变量要求存在符号表中;注:所有识别出的单词都用二元组表示。第一个表示单词的种类。关键字的 t=1;标识符的 t=2;常数 t=3;运算符 t=4;界符 t=5。第二个为该单词在各自表中的指针或内部码值(常数表和标识符表是在编译过程中建立起来的。其 i 值是根据它们在源程序中出现的顺序确定的)。关键字和特殊符号表格如下:单词代码12345678910名字intcharfloatvoidconstifelsedowhilescanf单词代码11121314151617181920名字printfreturnmain+*/%=单词代码21222324252627282930名字=><!=>=<=&&|!单词代码31323334353637383940名字();,“+-将词法分析程序设计成独(入口)立一遍扫描源程序的结构。其主流程图如下:四、程序源代码#include "stdafx.h"#include "词法分析.h"#include "词法分析Dlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE = _FILE_;#endif#define BUFFERSIZE 1200#define letter 1#define digit 0#define notld -1#define ksize 21#define ssize 25/char *kksize="main","int","float","double","for","while", "struct","do","char","if","else","return", "void","scanf","print","cout","cin","endl", "include","iostream","define"char *sssize="(",")","","","","=","+","*",">","<",",", / 1 2 3 4 5 6 7 8 9 10 11 "?",">=",">>","<=","<<","+","+=","-","-=","=", /12 13 14 15 16 17 18 19 20 21 "#","","","." /22char bufferBUFFERSIZE=""int placeBUFFERSIZE2;char ch;char strToken100=""int pp=0;char *biaoshifu100;int biao=0;char *constt100;int con=0;BOOL CMyDlg:OnInitDialog()CDialog:OnInitDialog();/ Add "About." menu item to system menu./ IDM_ABOUTBOX must be in the system command range.ASSERT(IDM_ABOUTBOX & 0xFFF0) = IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL)CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);/ Set the icon for this dialog. The framework does this automatically/ when the application's main window is not a dialogSetIcon(m_hIcon, TRUE);/ Set big iconSetIcon(m_hIcon, FALSE);/ Set small iconUINT array3;for(int i=0;i<3;i+)arrayi = 100+i;m_StatusBar.Create(this); /创建状态栏窗口m_StatusBar.SetIndicators(array,sizeof(array)/sizeof(UINT); /添加面板for(int n=0;n<3;n+)m_StatusBar.SetPaneInfo(n,arrayn,0,290); /设置面板宽度/设置面板文本m_StatusBar.SetPaneText(0,"狂风制作");m_StatusBar.SetPaneText(1," 欢迎大家使用");m_StatusBar.SetPaneText(2," 有理想就有梦想");RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);SetTimer(1,300,NULL); /设置定时器return TRUE; / return TRUE unless you set the focus to a controlvoid CMyDlg:OnSysCommand(UINT nID, LPARAM lParam)if (nID & 0xFFF0) = IDM_ABOUTBOX)CAboutDlg dlgAbout;dlgAbout.DoModal();elseCDialog:OnSysCommand(nID, lParam);/ If you add a minimize button to your dialog, you will need the code below/ to draw the icon. For MFC applications using the document/view model,/ this is automatically done for you by the framework.void CMyDlg:OnPaint() if (IsIconic()CPaintDC dc(this); / device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);/ Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;/ Draw the icondc.DrawIcon(x, y, m_hIcon);elseCDialog:OnPaint();/ The system calls this to obtain the cursor to display while the user drags/ the minimized window.HCURSOR CMyDlg:OnQueryDragIcon()return (HCURSOR) m_hIcon;void CMyDlg:OnClickRichedit2(NMHDR* pNMHDR, LRESULT* pResult) / TODO: Add your control notification handler code here*pResult = 0;char* CMyDlg:print(int i)return ki;void CMyDlg:Onfenxi() / TODO: Add your control notification handler code here/CFile file(NULL,CFile:modeCreate|CFile:modeWrite); CString strText1=""CString strText2=""strText1=dealwith(); m_richedit2.SetWindowText(strText1);void CMyDlg:GetChar()ch=bufferpp;pp+;void CMyDlg:getbc()while (ch=' '|int(ch)=10)GetChar();void CMyDlg:concat()strcat(strToken,&ch);int CMyDlg:IsLetterorDigit()if ('a'<=ch&&ch<='z')|('A'<=ch&&ch<='Z')return letter;else if('0'<=ch&&ch<='9') return digit;else return notld;int CMyDlg:reserve()for (int i=0;i<ksize;i+)if(strcmp(strToken,ki)=0)return i+1;return 0;int CMyDlg:reserve1()for(int i=0;i<ssize;i+)if (strcmp(strToken,si)=0) return i+1;if(int(strToken0)=13)return -1;return 0;void CMyDlg:retract()ch=' 'pp-;int CMyDlg:insertid(char *a)biaoshifubiao+=a;return biao;int CMyDlg:insertConst(char *a)consttcon+=a;return con;CString CMyDlg:dealwith()CString strText="",str=""pp=0;int code,valuee;/code为单词种别标号 valuee为单词符号的属性值int place1=0;str +="单词符号 t单词类型t类型编码t行数,列数n"strText +=str;while (pp<BUFFERSIZE&&bufferpp!=NULL)for (int j=0;j<100;j+)strTokenj=NULL;GetChar();getbc();place1=pp-1;if(1=IsLetterorDigit()/ch里存放的是是字母while(1=IsLetterorDigit()|0=IsLetterorDigit()concat();GetChar();retract();code=reserve();if (code=0)valuee=insertid(strToken);str.Format("%stt标识符tt%dtt(%d,%d)n",strToken,0,placeplace10,placeplace11);elsestr.Format("%stt关键字tt%dtt(%d,%d)n",strToken,40+code,placeplace10,placeplace11);else if (digit=IsLetterorDigit()/返回是是数字int isletter=0;/判断数字后面是否是字母,如果是isletter=1,如果不是的话istetter=0while(digit=IsLetterorDigit()|(letter=IsLetterorDigit()|ch='.')if (letter=IsLetterorDigit() isletter=1;if (ch='.')isletter=2;concat();GetChar();retract();if (isletter=1)str.Format("%sttERRORtt%dtt(%d,%d)n",strToken,100,placeplace10,placeplace11);else if (isletter=2)valuee=insertConst(strToken);str.Format("%stt非整形常量tt%dtt(%d,%d)n",strToken,30,placeplace10,placeplace11);elsevaluee=insertConst(strToken);str.Format("%stt整形常量tt%dtt(%d,%d)n",strToken,31,placeplace10,placeplace11);else if (-1=IsLetterorDigit() /既非数字,又非字母,是界符,运算符等等,int i=0;switch(ch)case '>':while(-1=IsLetterorDigit()&&ch!=' '&&ch!=NULL&&int(ch)!=13) concat();GetChar();if(int(ch)!=13)retract();break;case '<':while(-1=IsLetterorDigit()&&ch!=' '&&ch!=NULL&&int(ch)!=13) concat();GetChar();if(int(ch)!=13)retract();break;case '+':while(-1=IsLetterorDigit()&&ch!=' '&&ch!=NULL&&int(ch)!=13) concat();GetChar();if(int(ch)!=13)retract();break;case '-':while(-1=IsLetterorDigit()&&ch!=' '&&ch!=NULL&&int(ch)!=13) concat();GetChar();if(int(ch)!=13)retract();break;case '=':while(-1=IsLetterorDigit()&&ch!=' '&&ch!=NULL&&int(ch)!=13) concat();GetChar();if(int(ch)!=13)retract();break;default: concat();break;i=reserve1();if (i=0)str.Format("%sttERRORtt%dtt(%d,%d)n",strToken,100,placeplace10,placeplace11);else if(i!=-1)str.Format("%stt算符tt%dtt(%d,%d)n",strToken,i,placeplace10,placeplace11);strText +=str;str ="" return strText;void CMyDlg:OnButtonopen() / TODO: Add your control notification handler code here/ TODO: Add your control notification handler code hereCFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"All Files(*.*)|*.*| |",AfxGetMainWnd();/CMyApp aa;CString strPath,strText=""if(dlg.DoModal() = IDOK)strPath=dlg.GetPathName();CFile file(strPath,CFile:modeRead);char read1000;char c; /定义变量 c记录当前从文件中读入的一个字符int row=1; /记录文件的行数int line=1; /记录文件的列数int j=0;file.Read(read,1000);for(int i=0;i<file.GetLength();i+)strText += readi;c =readi;if (c='n')/回车换行列数变为1,行数加1line =1;row +=1;if (int(c)!=13|char(c)!=0)bufferi=c;placej0=row;placej1=line;j+;if (int(c)!=0)line +=1;file.Close();m_richedit1.SetWindowText(strText);/char* temp;/temp=print(1);/strText2 +="lll"/strText2 +=temp;/*for( i=0;i<21;i+)temp=print(i);strText2 +=temp;strText2 +='t'if(i+1)%5=0)strText2 +='n'*/MessageBox(temp,"sadf",MB_OK);/*m_richedit1.SetWindowText(strText); i=0; char ch; ch=strText0;while(i<100) ch=strTexti+;strText2 +=ch;strText2 +="n#"m_richedit2.SetWindowText(strText2);*/UpdateData(FALSE);void CMyDlg:OnButtonsave() / TODO: Add your control notification handler code hereCFileDialog dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"All Files(*.*)|*.*| |",AfxGetMainWnd();CString strPath,strText=""char write1000;if(dlg.DoModal()=IDOK)strPath=dlg.GetPathName();if(strPath.Right(4)!=".txt")strPath+=".txt"CFile file(_T(strPath),CFile:modeCreate|CFile:modeWrite);m_richedit2.GetWindowText(strText);strcpy(write,strText);file.Write(write,strText.GetLength();file.Close();void CMyDlg:OnTimer(UINT nIDEvent) / TODO: Add your message handler code here and/or call defaultCString sText,sleft,sright;int len;sText = m_StatusBar.GetPaneText(2); /获得状态栏第3个面板的显示字符len = sText.GetLength();sright = sText.Left(2);sleft = sText.Right(len-2);sText = sleft + sright;m_StatusBar.SetPaneText(2,sText); /设置状态栏第3个面板的显示字符CDialog:OnTimer(nIDEvent);void CMyDlg:OnMenuopen() / TODO: Add your command handler code hereOnButtonopen();void CMyDlg:OnMenusave() / TODO: Add your command handler code hereOnButtonsave();void CMyDlg:OnMenufnxi() / TODO: Add your command handler code hereOnfenxi();void CMyDlg:OnMeuabout() / TODO: Add your command handler code hereCAboutDlg aboutDlg;aboutDlg.DoModal();void CMyDlg:OnMenuexit() / TODO: Add your command handler code hereexit(0);五、运行结果六、小结(不少于100字)通过这次实验,我们初步掌握了词法分析的简单的实现方法。本次编写的程序要实现输出源程序对应的二元组、对错误单词能够报错并提示出错误所在行等功能。通过设计调试词法分析程序,从而实现从源程序中分出各种单词,同时也能加深我们对课堂教学的理解,深刻理解词法分析的整个过程,提高词法分析方法的实践能力。