📄 scannerdlg.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 + -