SstudentT 发表于 2015-6-8 14:02

桌面计算器,递归下降分析,Qt框架。代码。

本帖最后由 SstudentT 于 2015-6-9 12:47 编辑

大概思路:
首先,用Qt框架写个界面。实现能够对鼠标点击输入以及键盘输入,用到Qt有的信号和槽,还有通用的事件处理。
其次,用递归下降思路写个计算表达式的类,
1.parse_expression
2.parse_term
3.parse_primary_expression
第一个解决 + -操作!
第二个解决 * /操作!
第三个解决数的读取!

递归下降体现在:
第三个数的读取,如果碰到的是括号。就把括号里面的当初一个expression,调用第一个parse_expression来计算!

异常处理就是parse_expression主要代码放在 try{ }里面,下面各级发生词法错误或者语法错误就throw。然后在tyr{ }的后面catch{ }部分处理!
catch处理的时候判断这个是第几层parse_expression,如果是最外层parse_expression,处理了就结束了。如果不是最外层,就接着throw。

最后,把Qt写的界面和计算表达式的类结合一下。把行编辑器里面的内容最为计算类的计算对象。把对象的计算结果设置成行编辑器内容!

附上源码以及exe程序。链接:http://pan.baidu.com/s/1mgkTMxq
密码:efyz
忘记加了一句,大神请无视我!

头文件compute.h

#ifndef COMPUTE_H
#define COMPUTE_H

#include<QString>
#include<QChar>
#include<QDebug>
#include<stdexcept>
#include<iostream>
typedef enum{
    BADTOKEN,
    ENDOFLINE,
    NUMBER,
    ADDOP,
    SUBOP,
    MULOP,
    DIVOP,
    LEFTPAREN,
    RIGHTPAREN
}TOKENKIND;

typedef struct Token{
TOKENKIND kind;
double value;
QString str;
}Token;

typedef enum{
    INITIAL,
    INT_PART,
    FRAC_PART,
    DOT
}Status;

using std::runtime_error;

class Compute
{
public:
    Compute(QString expression,Token*Fuck,int initialize=0)
      :Lexpression(expression),
         ahead_token(Fuck),
         ErrorStatu(initialize),
         Look_ahead_exist(initialize),
         curpos(initialize),
         Parse_expression_level(initialize){}
    QString Printf();
    ~Compute(){}
private:
    QString Lexpression;
    QString ErrorMessage;
    Token *ahead_token;
    int ErrorStatu;
    int Look_ahead_exist;
    int curpos;
    int Parse_expression_level;
    void get_token(Token*token);
    void un_get_token(Token*token);
    void my_get_token(Token*token);
    double parse_primary_expression();
    double parse_term();
    double parse_expression();
};

#endif // COMPUTE_H


头文件mylineedit.h
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H

#include <QLineEdit>
#include<QMouseEvent>
#include<QString>
class MyLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit MyLineEdit(QWidget *parent = 0);
    MyLineEdit(QString text,QWidget*parent=0);
    void textUpdata(QString addText);
    void textRemove();
    void CurInit();
private:
    long CurPos;
protected:
    void mousePressEvent(QMouseEvent *event);
    void keyPressEvent(QKeyEvent *event);
};

#endif // MYLINEEDIT_H


头文件widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include<QWidget>
#include<QPushButton>
#include<QGridLayout>
#include<QLineEdit>
#include<QDebug>
#include"compute.h"
#include"mylineedit.h"
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
   
private:
    Ui::Widget*ui;
    QPushButton*button;
    QGridLayout*mainlayout;
    MyLineEdit*lineEdit;
private slots:
    void DigitClicked();
    void BackSpaceClicked();
    void EqualClicked();
    void LeftParenClicked();
    void RightParenClicked();
    void AddClicked();
    void SubClicked();
    void PowClicked();
    void MulClicked();
    void ClearAllClicked();
    void PointClicked();         

};
#endif // WIDGET_H




compute.cpp文件
#include "compute.h"


QString Compute::Printf()
{
    double v;
    v=parse_expression();
    if(ErrorStatu==0)
      return QString::number(v);
    else
      return ErrorMessage;
}
void Compute::get_token(Token* token)
{
    Status statu=INITIAL;
    QString temp;
    while (curpos<Lexpression.size()) {
      if(Lexpression.isDigit())
      {
            if(statu==INITIAL)
            {
                statu=INT_PART;
                temp.append(Lexpression);
                curpos++;
                continue;
            }else if(statu==INT_PART){
                temp.append(Lexpression);
                curpos++;
                continue;
            }else if(statu==DOT) {
                statu=FRAC_PART;
                temp.append(Lexpression);
                curpos++;
                continue;
            }else if(statu==FRAC_PART){
                temp.append(Lexpression);
                curpos++;
                continue;
            }
      }else if (Lexpression=='+') {
            if(statu==INT_PART||statu==FRAC_PART)
            {
                token->kind=NUMBER;
                token->value=temp.toDouble();
                token->str=temp;
                return;
            }else if (statu==INITIAL) {
                token->kind=ADDOP;
                token->value=0;
                token->str="+";
                curpos++;
                return;
            }else{
                token->kind=BADTOKEN;
                token->value=0;
                token->str="BADTOKEN";
                curpos++;
                return;
            }
      }else if (Lexpression=='-') {
            if(statu==INT_PART||statu==FRAC_PART)
            {
                token->kind=NUMBER;
                token->value=temp.toDouble();
                token->str=temp;
                return;
            }else if (statu==INITIAL) {
                token->kind=SUBOP;
                token->value=0;
                curpos++;
                token->str="-";
                return;
            }else{
                token->kind=BADTOKEN;
                token->value=0;
                token->str="BADTOKEN";
                curpos++;
                return;
            }
      }else if (Lexpression=='*') {
            if(statu==INT_PART||statu==FRAC_PART)
            {
                token->kind=NUMBER;
                token->value=temp.toDouble();
                token->str=temp;
                return;
            }else if (statu==INITIAL) {
                token->kind=MULOP;
                token->value=0;
                curpos++;
                token->str="*";
                return;
            }else{
                token->kind=BADTOKEN;
                token->str="BADTOKEN";
                token->value=0;
                curpos++;
                return;
            }
      }else if (Lexpression=='/') {
            if(statu==INT_PART||statu==FRAC_PART)
            {
                token->kind=NUMBER;
                token->value=temp.toDouble();
                token->str=temp;
                return;
            }else if (statu==INITIAL) {
                token->kind=DIVOP;
                token->value=0;
                curpos++;
                token->str="/";
                return;
            }else{
                token->kind=BADTOKEN;
                token->str="BADTOKEN";
                token->value=0;
                curpos++;
                return;
            }
      }else if (Lexpression=='(') {
            if(statu==INT_PART||statu==FRAC_PART)
            {
                token->kind=NUMBER;
                token->value=temp.toDouble();
                token->str=temp;
                return;
            }else if (statu==INITIAL) {
                token->kind=LEFTPAREN;
                token->value=0;
                curpos++;
                token->str="(";
                return;
            }else{
                token->kind=BADTOKEN;
                token->str="BADTOKEN";
                token->value=0;
                curpos++;
                return;
            }
      }else if (Lexpression==')') {
            if(statu==INT_PART||statu==FRAC_PART)
            {
                token->kind=NUMBER;
                token->value=temp.toDouble();
                token->str=temp;
                return;
            }else if (statu==INITIAL) {
                token->kind=RIGHTPAREN;
                token->value=0;
                curpos++;
                token->str=")";
                return;
            }else{
                token->kind=BADTOKEN;
                token->str="BADTOKEN";
                token->value=0;
                curpos++;
                return;
            }
      }else if (Lexpression=='.') {
            if(statu==INT_PART)
            {
                statu=DOT;
                temp.append(Lexpression);
                curpos++;
            continue;
            }else{
                token->kind=BADTOKEN;
                token->str="BADTOKEN";
                token->value=0;
                curpos++;
                return;
            }
      }else if(Lexpression==' '){
                curpos++;
                continue;
      }
      else {
         token->kind=BADTOKEN;
         token->str="BADTOKEN";
         token->value=0;
         curpos++;
         return;
      }
    }
    if(statu==INITIAL)
    {
      token->kind=ENDOFLINE;
      token->str="ENDOFLINE";
      token->value=0;
      return;
    }else if(statu==INT_PART||statu==FRAC_PART){
      token->kind=NUMBER;
      token->value=temp.toDouble();
      token->str=temp;
      return;
    }
    return;
}

void Compute::un_get_token(Token*token)
{
    QString str=token->str;
    Look_ahead_exist=1;
    ahead_token->kind=token->kind;
    ahead_token->value=token->value;
    ahead_token->str=str;
}

void Compute::my_get_token(Token *token)
{
    if(Look_ahead_exist==1){
      token->kind=ahead_token->kind;
      token->value=ahead_token->value;
      token->str=ahead_token->str;
      Look_ahead_exist=0;
    }else
      get_token(token);
}

double Compute::parse_primary_expression()
{
    Token token;
    double v;
    int negative=0;

    while (1) {
      my_get_token(&token);
      if(token.kind==NUMBER){
            v=token.value;
            if(negative==0)
            return v;
            else
            return -v;
      }else if(token.kind==SUBOP){
            if(negative==1)
                throw runtime_error("BAD INPUT IN LEXICAL!");
            else{
                negative=1;
                continue;
            }
      }else if (token.kind==LEFTPAREN) {
            Parse_expression_level++;
            v=parse_expression();
            Parse_expression_level--;
            my_get_token(&token);
            if(token.kind!=RIGHTPAREN)
                throw runtime_error("MISSING RIGHTPAREN!");
            else{
                if(negative==1)
                  return -v;
                else
                   return v;
            }
      }else if(token.kind==ENDOFLINE){
            throw runtime_error("ENDOFLINE!");
      }else
            throw runtime_error("BAD INPUT IN LEXICAL!");
}
}

double Compute::parse_term()
{
    Tokentoken;
    double v1,v2;
    v1=parse_primary_expression();
    while (1) {
      my_get_token(&token);
      if(token.kind==ENDOFLINE){
            un_get_token(&token);
            return v1;
      }else if(token.kind==MULOP){
            v2=parse_primary_expression();
            v1*=v2;
      }else if(token.kind==DIVOP){
            v2=parse_primary_expression();
            if(v2==0.0){
                throw runtime_error("DIVISOR CAN'T BE ZERO!");
            }else{
                v1/=v2;
            }
      }else if(token.kind==ADDOP||token.kind==SUBOP||token.kind==RIGHTPAREN){
            un_get_token(&token);
            return v1;
      }else if(token.kind==BADTOKEN){
            throw runtime_error("BAD INPUT IN LEXICAL!");
      }else{
            throw runtime_error("BAD INPUT IN SYNTAX!");
      }
    }
}

double Compute::parse_expression()
{
    Token token;
    double v1,v2;
    try{
      v1=parse_term();
      while (1) {
            my_get_token(&token);
            if(token.kind==ADDOP){
                v2=parse_term();
                v1+=v2;
            }else if (token.kind==SUBOP) {
                v2=parse_term();
                v1-=v2;
            }else if(token.kind==RIGHTPAREN){
             un_get_token(&token);
             return v1;
            }else if(token.kind==ENDOFLINE){
                un_get_token(&token);
                return v1;
            }else{
                throw runtime_error("BAD INPUT!");
            }
      }
    }catch (runtime_error err){
      ErrorStatu=1;
      ErrorMessage=err.what();
       if(Parse_expression_level)
       {
         Parse_expression_level--;

         throw runtime_error(err.what());
       }

    }
    return 32767.0;
}



mylineedit.cpp文件
#include "mylineedit.h"
#include"compute.h"
MyLineEdit::MyLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
}
MyLineEdit::MyLineEdit(QString text,QWidget *parent):QLineEdit(parent)
{
setText(text);
}

void MyLineEdit::mousePressEvent(QMouseEvent *event)
{
   QLineEdit::mousePressEvent(event);
   CurPos=cursorPosition();
}

void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
    if(event->key()==16777220)
    {
      QString content;
      int initialize=0;
      Token *Fuck=new Token;
      content=text();
      Compute expression(content,Fuck,initialize);
      setText(expression.Printf());
      delete Fuck;
    }
    else
      QLineEdit::keyPressEvent(event);
}

void MyLineEdit::textUpdata(QString addText)
{
    QString text=this->text();
    text.insert(CurPos,addText);
    setText(text);
    CurPos++;
}

void MyLineEdit::textRemove()
{
    if (CurPos==0)
      return;
    QString text=this->text();
    text.remove(CurPos-1,1);
    setText(text);
    CurPos--;
}

void MyLineEdit::CurInit()
{
    CurPos=0;
}




widget.cpp文件
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    mainlayout=new QGridLayout;

    lineEdit=new MyLineEdit("",this);
    mainlayout->addWidget(lineEdit,0,0,2,4);

    for(int bNum=0;bNum<10;bNum++)
    {
      button=new QPushButton(QString::number(bNum),this);
      connect(button,SIGNAL(clicked()),this,SLOT(DigitClicked()));
      mainlayout->addWidget(button,4+bNum/4,bNum%4,1,1);
    }

    button=new QPushButton("BackSpace",this);
    connect(button,SIGNAL(clicked()),this,SLOT(BackSpaceClicked()));
    mainlayout->addWidget(button,2,0,2,1);

    button=new QPushButton("=",this);
    connect(button,SIGNAL(clicked()),this,SLOT(EqualClicked()));
    mainlayout->addWidget(button,2,3,2,1);

    button=new QPushButton("(",this);
    connect(button,SIGNAL(clicked()),this,SLOT(LeftParenClicked()));
    mainlayout->addWidget(button,6,2,1,1);

    button=new QPushButton(")",this);
    connect(button,SIGNAL(clicked()),this,SLOT(RightParenClicked()));
    mainlayout->addWidget(button,6,3,1,1);

    button=new QPushButton("+",this);
    connect(button,SIGNAL(clicked()),this,SLOT(AddClicked()));
    mainlayout->addWidget(button,7,0,1,1);

    button=new QPushButton("-",this);
    connect(button,SIGNAL(clicked()),this,SLOT(SubClicked()));
    mainlayout->addWidget(button,7,1,1,1);

    button=new QPushButton("*",this);
    connect(button,SIGNAL(clicked()),this,SLOT(PowClicked()));
    mainlayout->addWidget(button,7,2,1,1);

    button=new QPushButton("/",this);
    connect(button,SIGNAL(clicked()),this,SLOT(MulClicked()));
    mainlayout->addWidget(button,7,3,1,1);

    button=new QPushButton("ClearAll",this);
    connect(button,SIGNAL(clicked()),this,SLOT(ClearAllClicked()));
    mainlayout->addWidget(button,2,1,2,1);

    button=new QPushButton("Point",this);
    connect(button,SIGNAL(clicked()),this,SLOT(PointClicked()));
    mainlayout->addWidget(button,2,2,2,1);

    mainlayout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(mainlayout);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::DigitClicked()
{
    QPushButton*clickedButton=qobject_cast<QPushButton*>(sender());
    int digitValue=clickedButton->text().toInt();
    if(lineEdit->text()=="0"&&digitValue==0.0)
      return;
    else{
      lineEdit->textUpdata(clickedButton->text());
    }
}

voidWidget::BackSpaceClicked()
{
    lineEdit->textRemove();
}

void Widget::LeftParenClicked()
{
    lineEdit->textUpdata("(");
}

void Widget::RightParenClicked()
{
    lineEdit->textUpdata(")");
}

void Widget::AddClicked()
{
   lineEdit->textUpdata("+");
}

void Widget::SubClicked()
{
   lineEdit->textUpdata("-");
}

void Widget::PowClicked()
{
   lineEdit->textUpdata("*");
}

void Widget::MulClicked()
{
    lineEdit->textUpdata("/");
}

void Widget::PointClicked()
{
    lineEdit->textUpdata(".");
}

void Widget::ClearAllClicked()
{
    lineEdit->setText("");
    lineEdit->CurInit();
}

void Widget::EqualClicked()
{
    QString content;
    int initialize=0;
    Token *Fuck=new Token;
    content=lineEdit->text();
    Compute expression(content,Fuck,initialize);
    lineEdit->setText(expression.Printf());
    delete Fuck;
}



main.cpp文件
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
   
    return a.exec();
}


1032621483 发表于 2015-6-8 14:10

好像很厉害的样子

我来看看来哦 发表于 2015-6-8 14:10

SstudentT 发表于 2015-6-8 18:50

我来看看来哦 发表于 2015-6-8 14:10
然而并没有什么用

大神请无视我。。。

SstudentT 发表于 2015-6-8 18:51

1032621483 发表于 2015-6-8 14:10
好像很厉害的样子

大神请无视我。

manbajie 发表于 2015-6-9 12:11

好东西   流弊啊

袭影于夜 发表于 2015-6-10 08:36

你是华软的?

SstudentT 发表于 2015-6-10 20:25

袭影于夜 发表于 2015-6-10 08:36
你是华软的?

额。。。不是。

眼里有星河 发表于 2015-6-14 20:12

虽然没看懂。不过支持下
页: [1]
查看完整版本: 桌面计算器,递归下降分析,Qt框架。代码。