⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scannerdlg.cpp

📁 通过设计编制调试一个具体的词法分析程序
💻 CPP
字号:
// ScannerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Scanner.h"
#include "ScannerDlg.h"
#include "ListDialog.h"
#include "afxcoll.h"
#include "string.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CScannerDlg dialog
/*关键字包括void,int,float,if,else,for,while,do,break,continue,return*/
CString keywords[]={"void","int","float","if","else","for","while","do","break","continue","return"};

CScannerDlg::CScannerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CScannerDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CScannerDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CScannerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CScannerDlg)
	DDX_Control(pDX, IDC_RICHTEXTCTRL1, m_nInput);
	DDX_Control(pDX, IDC_RICHTEXTCTRL2, m_nOutput);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CScannerDlg, CDialog)
	//{{AFX_MSG_MAP(CScannerDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, OnInOpen)
	ON_BN_CLICKED(IDC_BUTTON2, OnInSave)
	ON_BN_CLICKED(IDC_BUTTON3, OnOutSave)
	ON_BN_CLICKED(IDC_BUTTON4, OnPredo)
	ON_BN_CLICKED(IDC_BUTTON5, OnScan)
	ON_BN_CLICKED(IDC_BUTTON6, OnListView)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CScannerDlg message handlers

BOOL CScannerDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	GetDlgItem(IDC_BUTTON5)->EnableWindow(false);
    GetDlgItem(IDC_BUTTON6)->EnableWindow(false);
	return TRUE;  // return TRUE  unless you set the focus to a control
}

// 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 CScannerDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int 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 icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CScannerDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

/////////////////////////////////////////////////////////////////////////////
//打开源程序文件
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::OnInOpen() 
{
	CString Buf;
        //打开文件对话框
	CFileDialog OFile(true,"*.txt","*.txt",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"Text Files(*.txt)|*.txt|C++ Files(*.cpp)|*.cpp|All Files(*.*)|*.*||");
	if(OFile.DoModal()==IDOK)
	{
		CString FileName=OFile.GetPathName();//获取当前文件路径
	    CFile file;
		file.Open(FileName,CFile::modeRead);//打开文件
		UINT FileSize=file.GetLength();//获取文件大小
		file.Read(Buf.GetBuffer(FileSize),FileSize);//将文件内容读进缓冲区
		m_nInput.SetText(Buf);//将文件内容显示在文本控件中
		file.Close();//关闭文件
	}
}


/////////////////////////////////////////////////////////////////////////////
//保存源程序文件
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::OnInSave() 
{
	CString Buf;
	//打开文件对话框
	CFileDialog OFile(false,"*.txt","*.txt",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"Text Files(*.txt)|*.txt|C++ Files(*.cpp)|*.cpp|All Files(*.*)|*.*||");
	if(OFile.DoModal()==IDOK)
	{
		CString FileName=OFile.GetPathName();//获取当前文件路径
	    CFile file;
		file.Open(FileName,CFile::modeCreate|CFile::modeWrite);//打开文件
		Buf=m_nInput.GetText();//将文本控件内容读进缓冲区
		UINT FileSize=Buf.GetLength();//获取缓冲区内容大小
		file.Write(Buf.GetBuffer(FileSize),FileSize);//将缓冲区内容写进文件
		file.Close();//关闭文件
	}
}

/////////////////////////////////////////////////////////////////////////////
//保存词法分析结果
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::OnOutSave() 
{
	CString Buf;
	//打开文件对话框
	CFileDialog OFile(false,"*.txt","*.txt",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"Text Files(*.txt)|*.txt|C++ Files(*.cpp)|*.cpp|All Files(*.*)|*.*||");
	if(OFile.DoModal()==IDOK)
	{
		CString FileName=OFile.GetPathName();//获取当前文件路径
	    CFile file;
		file.Open(FileName,CFile::modeCreate|CFile::modeWrite);//打开文件
		Buf=m_nOutput.GetText();//将文本控件内容读进缓冲区
		UINT FileSize=Buf.GetLength();//获取缓冲区内容大小
		file.Write(Buf.GetBuffer(FileSize),FileSize);//将缓冲区内容写进文件
		file.Close();//关闭文件
	}
}

/////////////////////////////////////////////////////////////////////////////
//判断一个字符是否为字母,是则返回true,否则返回false
/////////////////////////////////////////////////////////////////////////////
BOOL CScannerDlg::IsLetter(char ch)
{
	if(isalpha(ch)) return true;
	return false;
}

/////////////////////////////////////////////////////////////////////////////
//判断一个字符是否为数字,是则返回true,否则返回false
/////////////////////////////////////////////////////////////////////////////
BOOL CScannerDlg::IsDigit(char ch)
{
    if(isdigit(ch)) return true;
	return false;
}

/////////////////////////////////////////////////////////////////////////////
//判断一个字符是否为空白符(除"\n"),是则返回true,否则返回false
/////////////////////////////////////////////////////////////////////////////
BOOL CScannerDlg::IsSpace(char ch)
{
    if(isspace(ch)&&ch!='\n') return true;
	return false;   
}

/////////////////////////////////////////////////////////////////////////////
//判断是否为关键字,是则返回三元表达式,否则返回空串
/////////////////////////////////////////////////////////////////////////////
CString CScannerDlg::Reserve(CString strToken)
{
	CString str1="";
	for(int i=0;i<sizeof(keywords)/sizeof(CString);i++)
		if(strToken==keywords[i]) 
		{
			CString str2=keywords[i];
			str2.MakeUpper();
			str1.Format("<%d,%s,$%s>\r\n",22+i,keywords[i],str2);
			return str1;
		}//关键字格式化输出
	return "";//非关键字返回空串
}

/////////////////////////////////////////////////////////////////////////////
//预处理子程序
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::PreProcess()
{
	NewStr="";
    //人为添加'\n'置源程序末,防止预读访问不该访问的内存
	StrIn=m_nInput.GetText()+'\n';
	int i=0,len=StrIn.GetLength();
	char ch;
    while(i<len-1)//不考虑最后的'\n'
	{
		ch=StrIn[i];//获取当前字符
	    if(ch=='/'&&StrIn[i+1]=='/')//用“//”的注释删至行尾
		{
			while(StrIn[i]!='\n') i++;
			i-=1;//回退保留'\n'
		}
		else if(ch=='/'&&StrIn[i+1]=='*')//删除“/*”和“*/”之间的注释,找不到“*/”则删除至文件末
		{
			i+=2;//指向“/*”后的第一个字符
			while(StrIn[i]!='*'||StrIn[i+1]!='/') 
			{
				//防止越界访问
				if(i<len-2) i++;
				else break;
			}
			i+=1;//指向注释的结束位置
                        NewStr+=' ';//“/*”和“*/”之间的注释用空格代替
		}
        else if(IsSpace(ch)&&IsSpace(StrIn[i+1]));//多个相邻的空白符只保留一个
		else NewStr+=ch;
		i++;
	}
	return;
}

/////////////////////////////////////////////////////////////////////////////
//预处理按钮事件
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::OnPredo() 
{
	PreProcess();//调用预处理子程序
	m_nInput.SetText(NewStr);//显示预处理后的源程序
	GetDlgItem(IDC_BUTTON5)->EnableWindow(true);
	return;
}

/////////////////////////////////////////////////////////////////////////////
//词法分析子程序
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::Scan()
{
	int i=0;
	char ch;
	NewStr+='\n';//人为添加'\n'置预处理过的源程序末,防止预读访问不该访问的内存 
	IdList.RemoveAll();//清空标识符表
	ConstList.RemoveAll();//清空常数表
 	while(i<NewStr.GetLength()-1)//不考虑最后的'\n'
	{
		StrToken="";//置单词为空
		ch=NewStr[i];//获取当前字符
		if(IsLetter(ch))//当前字符为字母
		{
			StrToken+=ch;
			//判断是否为标识符
			while(IsLetter(NewStr[i+1])||IsDigit(NewStr[i+1])||NewStr[i+1]=='_')
			{
				StrToken+=NewStr[i+1];
				i++;
			}
			//调用函数Reserve,返回值不为空则为关键字,否则为一般标识符
			CString temp1=Reserve(StrToken);
            if(temp1=="") 
			{
				StrOut+="<1,"+StrToken+",$ID>\r\n";
				InsertId(StrToken);
			}
			else StrOut+=temp1;
		}
		else if(IsDigit(ch))//当前字符为数字
		{
			StrToken+=ch;
			//布尔变量flag1用来标记是否为实常数,flag2用来标记错误定义
			bool flag1=true,flag2=true;
            while(IsDigit(NewStr[i+1])||IsLetter(NewStr[i+1])||NewStr[i+1]=='_')
			{
				//数字开头且后跟字母或下划线,错误定义
				if(IsLetter(NewStr[i+1])||NewStr[i+1]=='_') flag2=false;
				StrToken+=NewStr[i+1];
				i++;
			}
			if(NewStr[i+1]=='.'&&IsDigit(NewStr[i+2]))//下一字符为'.'且下下个字符为数字,则认为是实常数 
			{
				flag1=false;
				StrToken+='.';
				i=i+1;
				while(IsDigit(NewStr[i+1]))
				{
				   StrToken+=NewStr[i+1];
				   i++;
				}
			}
			if(flag1&&flag2) //整常数
			{
				StrOut+="<2,"+StrToken+",$NUM>\r\n";
				InsertConst(StrToken);
			}
			else if(flag2) //实常数
			{
				StrOut+="<3,"+StrToken+",$REAL>\r\n";
				InsertConst(StrToken);
			}

			//错误定义
			else StrOut+="error:"+StrToken+" not defined\r\n";
		}
		else if(ch=='+') StrOut+="<4,+,$ADD>\r\n";//当前字符为'+',返回'+'
        else if(ch=='-') StrOut+="<5,-,$SUB>\r\n";//当前字符为'-',返回'-'
		else if(ch=='*') StrOut+="<6,*,$MUL>\r\n";//当前字符为'*',返回'*'
		else if(ch=='/') StrOut+="<7,/,$DIV>\r\n";//当前字符为'/',返回'/'
		else if(ch=='%') StrOut+="<8,%,$MOD>\r\n";//当前字符为'%',返回'%'
		else if(ch=='<')//当前字符为'<' 
		{
			if(NewStr[i+1]=='=')//预读下一字符,判断是否为'<=' 
			{
				StrOut+="<10,<=,$LE>\r\n";
				i+=1;
			}
			else StrOut+="<9,<,$LT>\r\n";
		}
        else if(ch=='>') //当前字符为'>' 
		{
			if(NewStr[i+1]=='=')//预读下一字符,判断是否为'>='  
			{
				StrOut+="<12,>=,$GE>\r\n";
				i+=1;
			}
			else StrOut+="<11,>,$GT>\r\n";
		}
        else if(ch=='=') //当前字符为'=' 
		{
			if(NewStr[i+1]=='=')//预读下一字符,判断是否为'=='  
			{
				StrOut+="<13,==,$EQ>\r\n";
				i+=1;
			}
			else StrOut+="<15,=,$ASSIGN>\r\n";
		}
		else if(ch=='!'&&NewStr[i+1]=='=')//当前字符为'!'且下一字符为'=',则认为是'!=' 
		{
			StrOut+="<14,!=,$NE>\r\n";
                	i+=1;
		}
		else if(ch=='(') StrOut+="<16,(,$LPAR>\r\n";//当前字符为'('
        else if(ch==')') StrOut+="<17,),$RPAR>\r\n";//当前字符为')'
		else if(ch=='[') StrOut+="<18,[,$LSB>\r\n";//当前字符为'['
		else if(ch==']') StrOut+="<19,],$RSB>\r\n";//当前字符为']'
		else if(ch=='{') StrOut+="<20,{,$LBR>\r\n";//当前字符为'{'
		else if(ch=='}') StrOut+="<21,},$RBR>\r\n";//当前字符为'}'
		else if(ch==',') StrOut+="<33,,,$COMMA>\r\n";//当前字符为','
		else if(ch==';') StrOut+="<34,;,$SEMI>\r\n";//当前字符为';'
		else if(ch==13||ch==' '||ch==10) ;//当前字符为空格、回车、换行时跳过
		else //其余均为错误定义,并显示错误
		{
			CString temp2="error:";
			temp2+=ch;
			temp2+=" not defined\r\n";
			StrOut+=temp2;
		}
		i++;
	}
	return;
}

/////////////////////////////////////////////////////////////////////////////
//词法分析按钮事件
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::OnScan() 
{
	StrOut="";//置词法分析结果显示为空
	Scan();//调用词法分析子程序
	m_nOutput.SetText(StrOut);//显示词法分析结果
    GetDlgItem(IDC_BUTTON6)->EnableWindow(true);//使查表按钮有效
	GetDlgItem(IDC_BUTTON5)->EnableWindow(false);//使扫描按钮无效
	return;
}

/////////////////////////////////////////////////////////////////////////////
//将标识符添加至标识符表
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::InsertId(CString str)
{
	for(int i=0;i<IdList.GetSize();i++)
		if(str==IdList[i]) break;//当前标识符存在则跳出循环
	if(i==IdList.GetSize()) IdList.Add(str);//添加新标识符
	return;

}

/////////////////////////////////////////////////////////////////////////////
//将常数添加至常数表
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::InsertConst(CString str)
{
    for(int i=0;i<ConstList.GetSize();i++)
		if(str==ConstList[i]) break;//当前常数存在则跳出循环
	if(i==ConstList.GetSize()) ConstList.Add(str);//添加新常数
	return;
}

/////////////////////////////////////////////////////////////////////////////
//查表按钮事件
/////////////////////////////////////////////////////////////////////////////
void CScannerDlg::OnListView() 
{
	CListDialog ListDlg(this);
	GetDlgItem(IDC_BUTTON6)->EnableWindow(false);//使查表按钮无效
	ListDlg.DoModal();		
	return;
}

/////////////////////////////////////////////////////////////////////////////
//取出所有的标识符
/////////////////////////////////////////////////////////////////////////////
CString CScannerDlg::GetAllId()
{
	CString str="";
	for(int i=0;i<IdList.GetSize();i++)
	{
		CString str1;
		str1.Format("%-d,  %s\r\n",i+1,IdList[i]);
	    str+=str1;
	}//格式化
	return str;
}

/////////////////////////////////////////////////////////////////////////////
//取出所有的常数
/////////////////////////////////////////////////////////////////////////////
CString CScannerDlg::GetAllConst()
{
	CString str="";
	for(int i=0;i<ConstList.GetSize();i++)
	{
		CString str1;
		str1.Format("%-d,  %s\r\n",i+1,ConstList[i]);
	    str+=str1;
	}//格式化
	return str;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -