Commit 2db15e0c authored by Han Young's avatar Han Young
Browse files

merge binary mode

parents 72bdaf3c 4bce7b54
......@@ -5,6 +5,7 @@ add_library(knumber STATIC
knumber_fraction.cpp
knumber_integer.cpp
knumber_operators.cpp
knumber_binary_wrapper.cpp
)
target_include_directories(knumber PUBLIC ${CMAKE_BINARY_DIR} ${GMP_INCLUDE_DIR})
......
/*
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "knumber_binary_wrapper.h"
#include "knumber.h"
#include <QString>
#include <QRegularExpression>
#include <QLatin1String>
#include <QDebug>
// Constructors and Destructors
BinaryNumber::BinaryNumber(const BinaryNumber& other) {
m_number = other.toKNum();
}
BinaryNumber::BinaryNumber(const KNumber &num) {
m_number = num;
}
BinaryNumber::BinaryNumber(const QString &s) : m_number(KNumber("UNDEFINED_ERROR")) {
const QRegularExpression binary_regex("^[01]+.[01]+|^[01]+");
if (binary_regex.match(s).hasMatch()) {
m_number = KNumber(0);
int seperator_loc = s.indexOf('.');
if (seperator_loc == -1) seperator_loc = s.length();
KNumber multiplier(1);
KNumber base(2);
// Integer Part Calculations
for (int idx = seperator_loc - 1; idx >= 0; idx--) {
m_number += (KNumber(s.at(idx)) * multiplier);
multiplier *= base;
}
// multiplier = base;
// // Fractional Part Calculations
// for (int idx = seperator_loc + 1; idx < s.length(); idx++) {
// m_number += (KNumber(s.at(idx)) / base);
// multiplier *= base;
// }
}
}
// Converters
QString BinaryNumber::toDec() const {
return m_number.toQString();
}
KNumber BinaryNumber::toKNum() const {
return m_number;
}
// Operators
BinaryNumber &BinaryNumber::operator=(const BinaryNumber &rhs) {
(*this).m_number = rhs.toKNum();
return *this;
}
BinaryNumber operator+(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res += rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator-(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res -= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator*(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res *= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator/(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res /= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator&(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res &= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator|(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res |= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator^(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res ^= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator<<(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res <<= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator>>(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res >>= rhs.toKNum();
return BinaryNumber(res);
}
/*
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <QString>
#include "knumber.h"
class BinaryNumber {
public:
// construction/destruction
BinaryNumber();
explicit BinaryNumber(const QString &s);
explicit BinaryNumber(const KNumber &num);
BinaryNumber(const BinaryNumber &other);
// ~BinaryNumber();
public:
// assignment
BinaryNumber &operator=(const BinaryNumber &rhs);
public:
// Unary operators
// KNumber &operator~();
public:
// Converters
QString toHex() const;
QString toOct() const;
QString toBin() const;
QString toDec() const;
KNumber toKNum() const;
private:
KNumber m_number;
};
BinaryNumber operator+(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator-(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator*(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator/(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator&(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator|(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator^(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator<<(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator>>(const BinaryNumber &lhs, const BinaryNumber &rhs);
......@@ -7,6 +7,8 @@
<file>qml/CalculationPage.qml</file>
<file>qml/FunctionPad.qml</file>
<file>qml/AboutPage.qml</file>
<file>qml/BinaryCalculator.qml</file>
<file>qml/BinaryPad.qml</file>
<file>qml/UnitConverter.qml</file>
</qresource>
</RCC>
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "inputmanager.h"
#include "mathengine.h"
#include "historymanager.h"
#include <QDebug>
InputManager::InputManager()
{
}
......@@ -43,7 +45,14 @@ void InputManager::append(const QString &subexpression)
}
m_moveFromResult = false;
MathEngine::inst()->parse(m_expression + subexpression);
// Call the corresponding parser based on the type of expression.
MathEngine * engineInstance = MathEngine::inst();
if (m_isBinaryMode) {
engineInstance->parseBinaryExpression(m_expression + subexpression);
} else {
engineInstance->parse(m_expression + subexpression);
}
if(!MathEngine::inst()->error())
{
m_stack.push_back(subexpression.size());
......@@ -60,7 +69,15 @@ void InputManager::backspace()
{
m_expression.chop(m_stack.back());
Q_EMIT expressionChanged();
MathEngine::inst()->parse(m_expression);
// Call the corresponding parser based on the type of expression.
MathEngine * engineInstance = MathEngine::inst();
if (m_isBinaryMode) {
engineInstance->parseBinaryExpression(m_expression);
} else {
engineInstance->parse(m_expression);
}
if(!MathEngine::inst()->error())
{
m_result = MathEngine::inst()->result();
......@@ -102,3 +119,8 @@ void InputManager::fromHistory(const QString &result)
Q_EMIT expressionChanged();
Q_EMIT resultChanged();
}
void InputManager::setBinaryMode(bool active) {
m_isBinaryMode = active;
clear();
}
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@Students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -22,6 +23,7 @@ public:
Q_INVOKABLE void equal();
Q_INVOKABLE void clear();
Q_INVOKABLE void fromHistory(const QString &result);
Q_INVOKABLE void setBinaryMode(bool active);
Q_SIGNALS:
void expressionChanged();
void resultChanged();
......@@ -31,5 +33,6 @@ private:
std::vector<int> m_stack; // track subexpression length for removal later
QString m_expression;
QString m_result;
bool m_isBinaryMode = false; // Changes the parser based on this variable
};
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "mathengine.h"
#include <QDebug>
#include <QRegularExpression>
#include <QStringList>
#include "knumber_binary_wrapper.h"
void MathEngine::parse(QString expr)
{
......@@ -11,3 +16,82 @@ void MathEngine::parse(QString expr)
m_result = QString::number(m_driver.result);
emit resultChanged();
}
QStringList getRegexMatches(QString expr, QString regex, int *counter) {
QRegularExpression re(regex);
QRegularExpressionMatch regexMatch;
QRegularExpressionMatchIterator it = re.globalMatch(expr);
QStringList matches;
while (it.hasNext()) {
regexMatch = it.next();
QString match = regexMatch.captured(0);
matches << match;
(*counter)++;
}
return matches;
}
void MathEngine::parseBinaryExpression(QString expr)
{
m_error = true;
qDebug() << "Current Epxression (mathengine.cpp): " << expr;
int numbersPresent = 0;
int operatorsPresent = 0;
// Match for the numbers and binary operators
QStringList numbers = getRegexMatches(expr, bitRegex, &numbersPresent);
QStringList operators = getRegexMatches(expr, binaryOperatorRegex, &operatorsPresent);
// Erroraneous Parses return here itself
if (
(operatorsPresent != 0 && numbersPresent == 0) ||
(operatorsPresent > 1) ||
(numbersPresent > 2)
) {
return;
} else {
m_error = false;
if (operatorsPresent == 0 && numbersPresent == 1) {
m_result = BinaryNumber(numbers[0]).toDec();
emit resultChanged();
}
}
// Binary Operator Syntax
if (expressionSyntaxRegex1.match(expr).hasMatch()) {
BinaryNumber result(0);
switch (operatorsList.indexOf(operators[0])) {
case 0: // +
result = BinaryNumber(numbers[0]) + BinaryNumber(numbers[1]);
break;
case 1: // -
result = BinaryNumber(numbers[0]) - BinaryNumber(numbers[1]);
break;
case 2: // *
result = BinaryNumber(numbers[0]) * BinaryNumber(numbers[1]);
break;
case 3: // /
result = BinaryNumber(numbers[0]) / BinaryNumber(numbers[1]);
break;
case 4: // &
result = BinaryNumber(numbers[0]) & BinaryNumber(numbers[1]);
break;
case 5: // |
result = BinaryNumber(numbers[0]) | BinaryNumber(numbers[1]);
break;
case 6: // ^
result = BinaryNumber(numbers[0]) ^ BinaryNumber(numbers[1]);
break;
case 7: // <<
result = BinaryNumber(numbers[0]) << BinaryNumber(numbers[1]);
break;
case 8: // >>
result = BinaryNumber(numbers[0]) >> BinaryNumber(numbers[1]);
break;
default: // error
m_error = true;
};
m_result = result.toDec();
emit resultChanged();
}
}
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -7,6 +8,8 @@
#define MATHENGINE_H
#include "mathengine/driver.hh"
#include <QObject>
#include <QRegularExpression>
#include <QStringList>
class MathEngine : public QObject
{
Q_OBJECT
......@@ -19,13 +22,14 @@ public:
return &singleton;
}
Q_INVOKABLE void parse(QString expr);
Q_INVOKABLE void parseBinaryExpression(QString expr);
QString result()
{
return m_result;
};
bool error()
{
return m_driver.syntaxError;
return m_driver.syntaxError || m_error;
};
signals:
void resultChanged();
......@@ -34,6 +38,15 @@ private:
MathEngine(){};
driver m_driver;
QString m_result;
bool m_error;
const QString bitRegex = QString("[01]+");
const QString binaryOperatorRegex = QString("[\\+\\-\\*\\/&\\|\\^]|<{2}|>{2}");
QRegularExpression expressionSyntaxRegex1 = QRegularExpression("([01]+)([\\+\\-\\*\\/&\\|~\\^]|<{2}|>{2})([01]+)");
QStringList operatorsList = {
"+", "-", "*", "/",
"&", "|", "^",
"<<", ">>"
};
};
#endif
......@@ -69,6 +69,7 @@
ASIN "ASIN"
ACOS "ACOS"
ATAN "ATAN"
ABS "ABS"
;
%token <double> NUMBER "number"
......@@ -112,6 +113,8 @@ exp:
| "ACOS" "(" exp ")" { $$ = acos($3); }
| "ATAN" "(" exp { $$ = atan($3); }
| "ATAN" "(" exp ")" { $$ = atan($3); }
| "ABS" "(" exp { $$ = fabs($3); }
| "ABS" "(" exp ")" { $$ = fabs($3);}
;
factor: "(" exp ")" { $$ = $2; }
......
......@@ -136,6 +136,7 @@ double [0-9]+|([0-9]+)?"."[0-9]+
"asin" return yy::parser::make_ASIN (loc);
"acos" return yy::parser::make_ACOS (loc);
"atan" return yy::parser::make_ATAN (loc);
"abs" return yy::parser::make_ABS (loc);
{double} return make_NUMBER (yytext, loc);
<<EOF>> return yy::parser::symbol_type (0, loc);
......
/*
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import QtQuick 2.7
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1 as Controls
import QtGraphicalEffects 1.12
import org.kde.kirigami 2.13 as Kirigami
Kirigami.Page {
id: initialPage
title: i18n("Calculator")
topPadding: 0
leftPadding: 0
rightPadding: 0
bottomPadding: 0
property color dropShadowColor: Qt.darker(Kirigami.Theme.backgroundColor, 1.15)
property int keypadHeight: {
let rows = 6, columns = 5;
// restrict keypad so that the height of buttons never go past 0.85 times their width
if ((initialPage.height - Kirigami.Units.gridUnit * 7) / rows > 0.85 * initialPage.width / columns) {
return rows * 0.85 * initialPage.width / columns;
} else {
return initialPage.height - Kirigami.Units.gridUnit * 7;
}
}
Keys.onPressed: {
switch(event.key) {
case Qt.Backspace || Qt.Delete:
inputManager.backspace(); break;
case Qt.Key_0:
inputManager.append("0"); break;
case Qt.Key_1:
inputManager.append("1"); break;
case Qt.Key_Plus:
inputManager.append("+"); break;
case Qt.Key_Minus:
inputManager.append("-"); break;
case Qt.Key_multiply:
inputManager.append("*"); break;
case Qt.Key_division:
inputManager.append("/"); break;
case Qt.Key_Ampersand:
inputManager.append("&"); break;
case Qt.Key_Bar:
inputManager.append("|"); break;
case Qt.Key_AsciiCircum:
inputManager.append("^"); break;
case Qt.Key_Period:
inputManager.append("."); break;
case Qt.Key_Equal:
case Qt.Key_Return:
case Qt.Key_Enter:
inputManager.equal(); break;
}
}
onIsCurrentPageChanged: {
inputManager.setBinaryMode(true)
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Rectangle {
id: outputScreen
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: initialPage.height - initialPage.keypadHeight
color: Kirigami.Theme.backgroundColor
Column {
id: outputColumn
anchors.fill: parent
anchors.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.gridUnit
Flickable {
anchors.right: parent.right
height: Kirigami.Units.gridUnit * 1.5
width: Math.min(parent.width, contentWidth)
contentHeight: expressionRow.height
contentWidth: expressionRow.width
flickableDirection: Flickable.HorizontalFlick
Controls.Label {
id: expressionRow
horizontalAlignment: Text.AlignRight
font.pointSize: Kirigami.Units.gridUnit
text: inputManager.expression
color: Kirigami.Theme.disabledTextColor
}
onContentWidthChanged: {
if(contentWidth > width)
contentX = contentWidth - width;
}
}
Flickable {
anchors.right: parent.right
height: Kirigami.Units.gridUnit * 4
width: Math.min(parent.width, contentWidth)
contentHeight: result.height
contentWidth: result.width
flickableDirection: Flickable.HorizontalFlick
Controls.Label {
id: result
horizontalAlignment: Text.AlignRight
font.pointSize: Kirigami.Units.gridUnit * 2
text: inputManager.result
NumberAnimation on opacity {
id: resultFadeInAnimation
from: 0.5
to: 1
duration: Kirigami.Units.shortDuration
}
NumberAnimation on opacity {
id: resultFadeOutAnimation
from: 1
to: 0
duration: Kirigami.Units.shortDuration
}
onTextChanged: resultFadeInAnimation.start()
}
}
}
}
// Binary Input Pad
Rectangle {
property string expression: ""
id: binaryInputPad
Layout.fillHeight: true
Layout.preferredWidth: initialPage.width
Layout.alignment: Qt.AlignLeft
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
color: Kirigami.Theme.backgroundColor
BinaryPad {
id: binaryPad
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing
// Uncomment next line for function overlay
// anchors.rightMargin: Kirigami.Units.gridUnit * 1.5
onPressed: {
if (text == "DEL") {
inputManager.backspace();
} else if (text == "=") {
inputManager.equal();
resultFadeOutAnimation.start();
} else {
inputManager.append(text, true);
}
}
onClear: inputManager.clear()
}
}
// top panel drop shadow (has to be above the keypad) - from main calculator
DropShadow {
anchors.fill: outputScreen
source: outputScreen
horizontalOffset: 0
verticalOffset: 1
radius: 4
samples: 6
color: initialPage.dropShadowColor
}
}
}
/*
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import QtQuick 2.0
import org.kde.kirigami 2.13 as Kirigami