📄 wjdlg.cpp
字号:
// wjDlg.cpp : implementation file
//
#include "stdafx.h"
#include "wj.h"
#include "wjDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
///////////////////////////////////////////////////////////////////////////////
// 名称:可编程计算器
// 功能描述:
// 本计算器可以实现对诸如 3+(1+7)*6+4*((5+4))这样的表达式的计算,
// 目前仅限于带括号的 +, * 运算
// 实现描述:
// 本计算器的是在教材 pp.49, 文法 (3.8)基础上稍加修改后,
// 利用自上而下的递归程序实现。每个非终结符对应一个分析函数。
//
// 修改后的文法如下所示,其中 e 代表空串
//
// E-->TE'
// E'-->+TE'|-TE'|e
// T-->FT'
// T'-->*FT'|/FT'|e
// F-->(E)|num
//
// 程序中使用了一个词法分析函数 yylex,变量yylval代表最近的整数
// 记号的数值。'\0'对应着$符号,预示着输入串结束.
//
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
// 这一段是极好的定义
#define ADD 0
#define MIN 1
#define MUL 2
#define DIV 3
#define LBRACE 4
#define RBRACE 5
#define NUM 6
#define END 7
#define OTHER 8
char input[200]; // 输入串。
int lookahead;
int pCur;
double yylval;
char last;
char before;
CString error;
// 函数声明
int yylex();
void Match(int t);
double T();
double E_();
double E();
double T_();
double F();
// 词法分析器,读入一个记号
int yylex()
{
char num[20];
int temp = 0;
// 过滤掉空白
while ( input[pCur]==' ' ) pCur++;
// 如果是数字(可以带小数点),那么把这个记号的数值计算出来放在 yylval 中
while (input[pCur] >= '0' && input[pCur] <= '9'||input[pCur]=='.'){
num[temp++] = input[pCur++];
}
if (temp >0)
{
sscanf(num, "%lf", &yylval);
return NUM;
}
last = input[pCur];
before = input[pCur-1];
// 其他记号的处理
switch (input[pCur++]) // 注意:这里指针往前移了一位
{
case '+': return ADD;
case '-': return MIN;
case '*': return MUL;
case '/': return DIV;
case '(': return LBRACE;
case ')': return RBRACE;
case '\0': return END;
default: return OTHER;
}
}
// 匹配函数,若当前记号与参数相同,则读入下一个记号
void Match(int t)
{
if (lookahead == t)
lookahead = yylex();
else
{
error = "括号不匹配,左括号和右括号必须成对出现!\n";
throw error;
}
}
// 处理 E-->TE'
double E()
{
switch (lookahead)
{
case LBRACE: // FIRST(E)={(,num}
case NUM:
return T() + E_();
case MIN:
Match(MIN);
return -T() + E_();
case END:
error = "";
error = error + "表达式不能以字符 " + before +" 结尾!\n表达式只能以右括号或数字结尾!\n";
throw error;
break;
default:
if(pCur == 1)
{
error = "";
error = error + "表达式不能以字符 "+ last +" 开头!\n表达式只能以左括号或数字开头!\n";
throw error;
}
else
{
error = "";
error = error + "左括号后不能跟字符 "+ last +" !\n左括号后只能跟左括号或数字!\n";
throw error;
}
}
}
// 处理 E'-->+TE'|-TE'|e
double E_()
{
switch (lookahead)
{
case ADD: // FIRST(E')={+,-,e}
Match(ADD);
return T() + E_();
case MIN:
Match(MIN);
return -T() + E_();
case RBRACE: // E'-->e 的情况,这个时候需要处理 FOLLOW集合, FOLLOW(E')={), $}
case END:
return 0;
default:
error = "不可能发生的错误!";
throw error; //这个错误一般不会发生,因为在他执行之前如果有错误的话一般会被发现。
}
}
// 处理 T-->FT'
double T()
{
switch (lookahead)
{
case LBRACE: // FIRST(T)={(,num}
case NUM:
return F()*T_();
case END:
error = "";
error = error + "\n表达式不能以操作符 "+ before +" 结尾!\n";
throw error;
default:
error = "";
error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
throw error;
}
}
// 处理 T'-->*FT'|/FT'|e
double T_()
{
switch (lookahead)
{
case MUL: // FIRST(T')={*,/,e}
Match(MUL);
return F() * T_();
case DIV:
Match(DIV);
return 1/F() * T_();
case ADD: // T'-->e 的情况,这个时候需要处理 FOLLOW集合, FOLLOW(T')={+,-,),$}
case MIN:
case RBRACE:
case END:
return 1;
case NUM:
error = "右括号后不能直接跟数字,只能跟+、-、*、/操作符!";
throw error;
default:
error = "";
error = error + "字符 + before + 后不能跟字符 " + last + " !\n数字或右括号后只能跟+、-、*、/和右括号!\n";
throw error;
}
}
// 处理 F-->(E)|num
double F()
{
double temp;
switch(lookahead)
{
case LBRACE: // FIRST((E))={(}
Match(LBRACE);
temp = E();
Match(RBRACE);
return temp;
case NUM: // FIRST(num) = {num}
temp = yylval;
Match(NUM);
return temp;
case END:
error = "";
error = error + "表达式不能以操作符 " + before + " 结尾!\n";
throw error;
default:
error = "";
error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
throw error;
}
}
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWjDlg dialog
CWjDlg::CWjDlg(CWnd* pParent /*=NULL*/)
: CDialog(CWjDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CWjDlg)
m_air = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CWjDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CWjDlg)
DDX_Text(pDX, IDC_EDIT1, m_air);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CWjDlg, CDialog)
//{{AFX_MSG_MAP(CWjDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
ON_BN_CLICKED(IDC_BUTTON4, OnButton4)
ON_BN_CLICKED(IDC_BUTTON5, OnButton5)
ON_BN_CLICKED(IDC_BUTTON6, OnButton6)
ON_BN_CLICKED(IDC_BUTTON7, OnButton7)
ON_BN_CLICKED(IDC_BUTTON8, OnButton8)
ON_BN_CLICKED(IDC_BUTTON9, OnButton9)
ON_BN_CLICKED(IDC_BUTTON10, OnButton10)
ON_BN_CLICKED(IDC_BUTTON11, OnButton11)
ON_BN_CLICKED(IDC_BUTTON12, OnButton12)
ON_BN_CLICKED(IDC_BUTTON13, OnButton13)
ON_BN_CLICKED(IDC_BUTTON14, OnButton14)
ON_BN_CLICKED(IDC_BUTTON15, OnButton15)
ON_BN_CLICKED(IDC_BUTTON16, OnButton16)
ON_BN_CLICKED(IDC_BUTTON17, OnButton17)
ON_BN_CLICKED(IDC_BUTTON18, OnButton18)
ON_BN_CLICKED(IDC_BUTTON19, OnButton19)
ON_BN_CLICKED(IDC_BUTTON20, OnButton20)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWjDlg message handlers
BOOL CWjDlg::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 dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CWjDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::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 CWjDlg::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 CWjDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CWjDlg::OnButton1()
{
// TODO: Add your control notification handler code here
m_air=m_air+"1";
UpdateData(FALSE);
}
void CWjDlg::OnButton2()
{
// TODO: Add your control notification handler code here
m_air=m_air+"2";
UpdateData(FALSE);
}
void CWjDlg::OnButton3()
{
// TODO: Add your control notification handler code here
m_air=m_air+"3";
UpdateData(FALSE);
}
void CWjDlg::OnButton4()
{
// TODO: Add your control notification handler code here
m_air=m_air+"4";
UpdateData(FALSE);
}
void CWjDlg::OnButton5()
{
// TODO: Add your control notification handler code here
m_air=m_air+"5";
UpdateData(FALSE);
}
void CWjDlg::OnButton6()
{
// TODO: Add your control notification handler code here
m_air=m_air+"6";
UpdateData(FALSE);
}
void CWjDlg::OnButton7()
{
// TODO: Add your control notification handler code here
m_air=m_air+"7";
UpdateData(FALSE);
}
void CWjDlg::OnButton8()
{
// TODO: Add your control notification handler code here
m_air=m_air+"8";
UpdateData(FALSE);
}
void CWjDlg::OnButton9()
{
// TODO: Add your control notification handler code here
m_air=m_air+"9";
UpdateData(FALSE);
}
void CWjDlg::OnButton10()
{
// TODO: Add your control notification handler code here
m_air=m_air+"0";
UpdateData(FALSE);
}
void CWjDlg::OnButton11()
{
// TODO: Add your control notification handler code here
m_air=m_air+"(";
UpdateData(FALSE);
}
void CWjDlg::OnButton12()
{
// TODO: Add your control notification handler code here
m_air=m_air+")";
UpdateData(FALSE);
}
void CWjDlg::OnButton13()
{
// TODO: Add your control notification handler code here
m_air=m_air+"+";
UpdateData(FALSE);
}
void CWjDlg::OnButton14()
{
// TODO: Add your control notification handler code here
m_air=m_air+"-";
UpdateData(FALSE);
}
void CWjDlg::OnButton15()
{
// TODO: Add your control notification handler code here
m_air=m_air+"*";
UpdateData(FALSE);
}
void CWjDlg::OnButton16()
{
// TODO: Add your control notification handler code here
m_air=m_air+"/";
UpdateData(FALSE);
}
void CWjDlg::OnButton17()
{
// TODO: Add your control notification handler code here
pCur = 0;
UpdateData(TRUE); // 从控件把文本传送到变量
int i;
for(i=0; i< m_air.GetLength(); i++)
input[i] = m_air[i];
input[i] = '\0';
lookahead = yylex();
double answer;
try
{
answer = E();
}
catch(CString error)
{
AfxMessageBox(error);
return;
}
if(lookahead != END)
{
AfxMessageBox("没有左括号和最后的右括号匹配!");
return;
}
char output[20];
_gcvt(answer, 5, output);
m_air = output;
if(m_air[m_air.GetLength()-1] == '.')
{
output[m_air.GetLength()-1] = '\0';
m_air = output;
}
UpdateData(FALSE); // 从变量把文本传送到控件
}
void CWjDlg::OnButton18()
{
// TODO: Add your control notification handler code here
m_air="";
UpdateData(FALSE);
}
void CWjDlg::OnButton19()
{
// TODO: Add your control notification handler code here
m_air.Delete(m_air.GetLength()-1);
UpdateData(FALSE);
}
void CWjDlg::OnButton20()
{
// TODO: Add your control notification handler code here
m_air=m_air+".";
UpdateData(FALSE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -