Working calculator.

This commit is contained in:
unlockable
2023-09-06 15:17:18 +08:00
parent 932faabd4a
commit 8126db644d
4 changed files with 916 additions and 55 deletions

209
.clang-format Normal file
View File

@@ -0,0 +1,209 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never

View File

@@ -1,10 +1,14 @@
#include "ListE.h"
#include "TimerOne.h" #include "TimerOne.h"
#include <string.h>
#define TIME_PER_LAYER_IN_US 800 #define TIME_PER_LAYER_IN_US 800
#define BUS_START_PIN 22 #define BUS_START_PIN 22
#define CLOCK_START_PIN 30 #define CLOCK_START_PIN 30
#define SW_START_PIN 38 #define SW_START_PIN 38
#define DEBUG false
class Cube { class Cube {
private: private:
static int layer_count; static int layer_count;
@@ -66,6 +70,365 @@ int Cube::brightness_count = 0;
int Cube::LED_status[8][8] = {0}; int Cube::LED_status[8][8] = {0};
int bright = 3; int bright = 3;
enum Operators {
plus,
minus,
multiply,
divide,
power,
left_parenthesis,
right_parenthesis,
};
enum CompareResult {
less,
equal,
greater,
};
class Symbol {
private:
bool is_symbol;
String name;
double value;
public:
static double *x_value_ptr, *y_value_ptr;
Symbol(String symbol_name) {
this->is_symbol = true;
this->name = symbol_name;
}
Symbol(double new_value) {
this->is_symbol = false;
this->value = new_value;
}
double get_value() const {
if (this->is_symbol) {
if (this->name == "x") {
return *x_value_ptr;
}
else if (this->name == "y") {
return *y_value_ptr;
}
}
return this->value;
}
};
class Operator {
private:
Operators name;
public:
Operator(const char op) {
if ('+' == op) {
this->name = plus;
}
else if ('-' == op) {
this->name = minus;
}
else if ('*' == op) {
this->name = multiply;
}
else if ('/' == op) {
this->name = divide;
}
else if ('^' == op) {
this->name = power;
}
else if ('(' == op) {
this->name = left_parenthesis;
}
else if (')' == op) {
this->name = right_parenthesis;
}
}
CompareResult compare(const Operator &other_operator) {
int self_priority, other_priority;
if (this->name == plus || this->name == minus) {
self_priority = 2;
}
else if (this->name == multiply || this->name == divide) {
self_priority = 4;
}
else if (this->name == power) {
self_priority = 6;
}
else if (this->name == left_parenthesis) {
self_priority = 8;
}
else if (this->name == right_parenthesis) {
self_priority = 1;
}
if (other_operator.name == plus || other_operator.name == minus) {
other_priority = 3;
}
else if (other_operator.name == multiply ||
other_operator.name == divide) {
other_priority = 5;
}
else if (other_operator.name == power) {
other_priority = 7;
}
else if (other_operator.name == left_parenthesis) {
other_priority = 1;
}
else if (other_operator.name == right_parenthesis) {
other_priority = 9;
}
if (self_priority < other_priority) {
return less;
}
else if (self_priority == other_priority) {
return equal;
}
else {
return greater;
}
}
Symbol calc(const Symbol first_pop, const Symbol second_pop) {
if (this->name == plus) {
return Symbol(first_pop.get_value() + second_pop.get_value());
}
else if (this->name == minus) {
return Symbol(second_pop.get_value() - first_pop.get_value());
}
else if (this->name == multiply) {
return Symbol(first_pop.get_value() * second_pop.get_value());
}
else if (this->name == divide) {
if (abs(first_pop.get_value()) <= 1e-5) {
return Symbol(atof("inf"));
}
return Symbol(second_pop.get_value() / first_pop.get_value());
}
else if (this->name == power) {
return Symbol(pow(second_pop.get_value(), first_pop.get_value()));
}
return 0.0;
}
bool operator==(Operators op) {
return this->name == op;
}
char display() {
switch (this->name) {
case plus:
return '+';
case minus:
return '-';
case multiply:
return '*';
case divide:
return '/';
case power:
return '^';
case left_parenthesis:
return '(';
case right_parenthesis:
return ')';
}
}
};
class Calculator {
private:
String expression;
List<Symbol> number_stack;
List<Operator> operator_stack;
int left_parenthesis_count;
void calculate() {
Operator operation = this->operator_stack.pop();
// this->operator_stack.pop();
Symbol number1 = this->number_stack.pop();
// this->number_stack.pop();
Symbol number2 = this->number_stack.pop();
// this->number_stack.pop();
this->number_stack.append(operation.calc(number1, number2));
}
public:
Calculator(const String expression) {
this->expression = expression + ')';
}
double evaluate() {
this->number_stack.clear();
this->operator_stack.clear();
this->operator_stack.append(Operator('('));
this->left_parenthesis_count = 1;
char operator_chars[] = "+-*/^()";
int operator_pos = -1;
while (true) {
if (DEBUG) {
Serial.println("A");
Serial.print("Operator pos: ");
Serial.println(operator_pos);
Serial.println("Number stack: ");
for (int i = 0; i < this->number_stack.length(); i++) {
Serial.println(this->number_stack[i].get_value());
}
Serial.println("Operator stack: ");
for (int i = 0; i < this->operator_stack.length(); i++) {
Serial.println(this->operator_stack[i].display());
}
}
bool found_next_operator = false;
int first_char_of_num = operator_pos + 1;
// operator_pos =
// this->expression.indexOf(operator_chars, operator_pos + 1);
operator_pos = this->expression.length();
for (int i = 0; i < sizeof(operator_chars); i++) {
int current_operator_pos = this->expression.indexOf(
operator_chars[i], first_char_of_num);
if (current_operator_pos < operator_pos &&
current_operator_pos >= 0) {
found_next_operator = true;
operator_pos = current_operator_pos;
}
}
if (!found_next_operator) {
break;
}
// Find the operator position
if (DEBUG) {
Serial.println("B");
Serial.print("Operator pos: ");
Serial.println(operator_pos);
Serial.println("Number stack: ");
for (int i = 0; i < this->number_stack.length(); i++) {
Serial.println(this->number_stack[i].get_value());
}
Serial.println("Operator stack: ");
for (int i = 0; i < this->operator_stack.length(); i++) {
Serial.println(this->operator_stack[i].display());
}
}
if (operator_pos != first_char_of_num) {
String number =
this->expression.substring(first_char_of_num, operator_pos);
if (number == "x" || number == "y") {
this->number_stack.append(Symbol(number));
}
else {
this->number_stack.append(Symbol(atof(number.c_str())));
}
}
else if (this->expression[operator_pos] == '-' &&
this->number_stack.length() ==
this->operator_stack.length() -
this->left_parenthesis_count) {
this->number_stack.append(0.0);
}
// Understand the number and push to stack
if (DEBUG) {
Serial.println("C");
Serial.print("Operator pos: ");
Serial.println(operator_pos);
Serial.println("Number stack: ");
for (int i = 0; i < this->number_stack.length(); i++) {
Serial.println(this->number_stack[i].get_value());
}
Serial.println("Operator stack: ");
for (int i = 0; i < this->operator_stack.length(); i++) {
Serial.println(this->operator_stack[i].display());
}
}
Operator current_operator(this->expression[operator_pos]);
if (current_operator == left_parenthesis) {
this->left_parenthesis_count += 1;
}
// Understand the operator
if (DEBUG) {
Serial.println("D");
Serial.print("Read operator: ");
Serial.println(current_operator.display());
Serial.print("Operator pos: ");
Serial.println(operator_pos);
Serial.println("Number stack: ");
for (int i = 0; i < this->number_stack.length(); i++) {
Serial.println(this->number_stack[i].get_value());
}
Serial.println("Operator stack: ");
for (int i = 0; i < this->operator_stack.length(); i++) {
Serial.println(this->operator_stack[i].display());
}
}
switch (current_operator.compare(this->operator_stack.peek())) {
case greater:
// Serial.println("Choose greater");
this->operator_stack.append(current_operator);
break;
case equal:
// Serial.println("Choose equal");
this->operator_stack.pop();
this->left_parenthesis_count -= 1;
break;
case less:
// Serial.println("Choose less");
if (this->number_stack.length() < 2) {
// Error
return atof("nan");
}
// Serial.println("Into Calc");
this->calculate();
// Serial.println("Out Calc");
// We only dealt with previous operators. Need to go through
// this operator again.
operator_pos--;
break;
}
if (DEBUG) {
Serial.println("E");
Serial.print("Operator pos: ");
Serial.println(operator_pos);
Serial.println("Number stack: ");
for (int i = 0; i < this->number_stack.length(); i++) {
Serial.println(this->number_stack[i].get_value());
}
Serial.println("Operator stack: ");
for (int i = 0; i < this->operator_stack.length(); i++) {
Serial.println(this->operator_stack[i].display());
}
}
}
if (this->left_parenthesis_count != 0) {
return 0.0;
}
return this->number_stack.peek().get_value();
}
};
double *Symbol::x_value_ptr, *Symbol::y_value_ptr;
double x, y;
void setup() { void setup() {
for (int i = 22; i < 46; i++) { for (int i = 22; i < 46; i++) {
pinMode(i, OUTPUT); pinMode(i, OUTPUT);
@@ -75,16 +438,52 @@ void setup() {
Timer1.setPeriod(TIME_PER_LAYER_IN_US); Timer1.setPeriod(TIME_PER_LAYER_IN_US);
Timer1.attachInterrupt(Cube::display); Timer1.attachInterrupt(Cube::display);
Serial.begin(115200); Serial.begin(9600);
Symbol::x_value_ptr = &x;
for (int x = 0; x < 8; x++) { Symbol::y_value_ptr = &y;
for (int y = 0; y < 8; y++) {
Cube::set_status(x, y, sqrt((x - 3) * (x - 3) + (y - 3) * (y - 3)), 3);
}
}
} }
void loop() { void loop() {
String input = "";
String allowed_chars = "0123456789+-*/^()xy";
while (true) {
if (Serial.available()) {
byte input_char = Serial.read();
// Serial.print("Pos: ");
// Serial.println(allowed_chars.indexOf(input_char));
if (allowed_chars.indexOf(input_char) != -1) {
input.concat((char)input_char);
// Serial.print("String: ");
// Serial.println(input);
continue;
}
if (input_char == 0x3) {
break;
}
}
}
Serial.print("Read: ");
Serial.println(input);
Calculator calculator(input);
Cube::clear();
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
double result = calculator.evaluate();
int z;
if (!(isinf(result) || isnan(result))) {
z = round(result);
Cube::set_status(x, y, z, 3);
}
Serial.print(x);
Serial.print(" ");
Serial.print(y);
Serial.print(" ");
Serial.println(z);
}
}
// int z = round(calculator.evaluate());
// Serial.println(z);
Serial.print("Here");
} }

148
8By8/ListE.h Normal file
View File

@@ -0,0 +1,148 @@
#include "Node.h"
template <class E> class List {
private:
Node<E> *head;
int _length;
int getIndexInRange(int index) const;
public:
List();
List(const E &newItem);
List(const E *newItemList, const int itemCount);
List(const List<E> &otherList);
~List();
// Append _newItem at last. Returns the List itself.
List<E> &append(const E &_newItem);
// Throws IndexError if index is not in the range of [-_length, _length -
// 1]. Returns the List itself.
E pop();
// Clear all nodes.
List<E> &clear();
const E &peek() const;
List<E> &operator=(const List<E> &otherList);
E &operator[](const int index);
const E &operator[](const int index) const;
int length() const;
bool empty() const;
};
template <class E> int List<E>::getIndexInRange(int index) const {
if (index < 0) {
index += this->_length;
}
if (index < 0 || index >= _length) {
return -1;
}
return index;
}
template <class E> List<E>::List() : head(NULL), _length(0){};
template <class E>
List<E>::List(const E &newItem) : head(new Node<E>(newItem)), _length(1){};
template <class E> List<E>::List(const E *newItemList, const int itemCount) {
for (int i = 0; i < itemCount; i++) {
this->append(newItemList[i]);
}
};
template <class E> List<E>::List(const List<E> &otherList) {
if (otherList.length() > 0) {
this->head = new Node<E>(otherList[0]);
this->_length = 1;
Node<E> *nextPtr = otherList.head->getNextPtr();
while (nextPtr != NULL) {
this->append((*nextPtr).getContent());
nextPtr = (*nextPtr).getNextPtr();
}
}
else {
this->head = NULL;
this->_length = 0;
}
}
template <class E> List<E>::~List() {
if (this->head != NULL) {
this->head->destruct();
}
head = NULL;
}
template <class E> List<E> &List<E>::append(const E &_newItem) {
if (this->head == NULL) {
this->head = new Node<E>(_newItem);
}
else {
this->head->getTail().setNext(new Node<E>(_newItem));
}
this->_length++;
return *this;
}
template <class E> E List<E>::pop() {
int index = this->_length - 1;
Node<E> removed = this->head->getByIndex(index);
this->_length--;
if (index == 0) {
Node<E> *newHead = this->head->getNextPtr();
delete this->head;
this->head = newHead;
}
else {
Node<E> &prev = this->head->getByIndex(index - 1);
delete prev.getNextPtr();
prev.setNext(removed.getNextPtr());
}
return removed.getContent();
}
template <class E> List<E> &List<E>::clear() {
if (this->_length == 0) {
return *this;
}
this->head->destruct();
this->head = NULL;
this->_length = 0;
return *this;
}
template <class E> const E&List<E>::peek() const {
return this->head->getByIndex(this->_length - 1).getContent();
}
template <class E> List<E> &List<E>::operator=(const List<E> &otherList) {
this->clear();
if (otherList.length() > 0) {
this->head = new Node<E>(otherList[0]);
this->_length = 1;
Node<E> *nextPtr = otherList.head->getNextPtr();
while (nextPtr != NULL) {
this->append((*nextPtr).getContent());
nextPtr = (*nextPtr).getNextPtr();
}
}
return *this;
}
template <class E> E &List<E>::operator[](const int index) {
return this->head->getByIndex(index).getContent();
}
template <class E> const E &List<E>::operator[](const int index) const {
return this->head->getByIndex(index).getContent();
}
template <class E> int List<E>::length() const {
return this->_length;
}
template <class E> bool List<E>::empty() const {
return this->_length == 0;
}

105
8By8/Node.h Normal file
View File

@@ -0,0 +1,105 @@
#pragma once
template <class E> class Node {
private:
E content;
Node *nextNode;
public:
Node();
Node(E _content, Node<E> *_nextNode = NULL);
~Node();
// Returns a reference to the content.
E &getContent();
// Returns a reference to the next Node. May return NULL if this Node is the
// last one.
Node<E> *getNextPtr();
// Set the next Node _nextNode. Returns original pointer.
Node<E> *setNext(Node<E> *_nextNode);
// Returns a reference to the Tail.
Node<E> &getTail();
// Returns a reference to the Node of given index.
Node<E> &getByIndex(const int index);
// Compare the content with the argument.
bool operator==(const E &other);
// Destructs the Node itself and all the node behind it.
void destruct();
};
template <class E> class Iterator {
private:
Node<E> *current;
public:
Iterator(Node<E> *pos);
bool hasNext();
// Return the same as hasNext();
operator bool();
E &next();
};
template <class E> Node<E>::Node() : content(0), nextNode(NULL){};
template <class E>
Node<E>::Node(E _content, Node *_nextNode)
: content(_content), nextNode(_nextNode){};
template <class E> Node<E>::~Node(){};
template <class E> E &Node<E>::getContent() {
return this->content;
}
template <class E> Node<E> *Node<E>::getNextPtr() {
return this->nextNode;
}
template <class E> Node<E> *Node<E>::setNext(Node<E> *_nextNode) {
Node<E> *temp = this->nextNode;
this->nextNode = _nextNode;
return temp;
}
template <class E> Node<E> &Node<E>::getTail() {
if (this->nextNode == NULL) {
return *this;
}
return this->nextNode->getTail();
}
template <class E> Node<E> &Node<E>::getByIndex(const int index) {
if (index == 0) {
return *this;
}
return this->nextNode->getByIndex(index - 1);
}
template <class E> bool Node<E>::operator==(const E &other) {
return this->content == other;
}
template <class E> void Node<E>::destruct() {
if (this->nextNode != NULL) {
this->nextNode->destruct();
}
delete this;
}
template <class E> Iterator<E>::Iterator(Node<E> *start) : current(start){};
template <class E> bool Iterator<E>::hasNext() {
return this->current != NULL;
}
template <class E> Iterator<E>::operator bool() {
return this->hasNext();
}
template <class E> E &Iterator<E>::next() {
if (!this->hasNext()) {
throw(IndexError("Out of bound!"));
}
E &temp = this->current->getContent();
this->current = this->current->getNextPtr();
return temp;
}