316 lines
7.8 KiB
C++

#include <stdio.h>
#include <string.h>
#include <windows.h>
//#include "math_graphics.h"
#include <math.h>
#include <setjmp.h>
#include "m_string.h"
enum TokenKind {
ENDOFINPUT, INTEGER, KOMMA, PLUS, MINUS, MUL, DIV, MODULO, LPAREN, RPAREN, POW, SQRT, SIN, COS, TAN, ATAN, ATAN2, ANS
};
//Definition Token
struct Token {
TokenKind kind = ENDOFINPUT;
double floatValue;
long intValue;
};
//Erkennen ob Leerzeichen, Zeilenumbruch, Tabulator etc.
bool isWhitespace(char c) {
if (c == ' ' || c == '\n' || c == '\t' || c == '\r') {
return true;
}
return false;
}
//Wenn Whitsepace weitergehen
void eatWhitespace(String &s) {
while (isWhitespace(s[0])) {
advance(s);
}
}
bool isNumber(char c) {
if ('0' <= c && c <= '9') {
return true;
}
return false;
}
long parseInteger(String inputString) {
long integerValue = 0;
for (int currentPosition = 0; currentPosition < inputString.length; currentPosition++) {
integerValue = integerValue * 10 + inputString[currentPosition] - '0';
}
return integerValue;
}
double parseFloat(String inputString) {
double floatValue = 0.0;
int currentPosition = 0;
for (; currentPosition < inputString.length; currentPosition++) {
if (inputString[currentPosition] == '.') {
currentPosition++;
break;
}
floatValue = floatValue * 10.0 + (inputString[currentPosition] - '0');
}
double floatValue2 = 0.0;
for (int currentPosition2 = inputString.length - 1; currentPosition2 >= currentPosition; currentPosition2--) {
floatValue2 = floatValue2 / 10.0 + (inputString[currentPosition2] - '0');
}
return floatValue + (floatValue2 / 10);
}
//Funktion zur Erkennung neuer Token
Token getNextToken(String &inputString) {
Token token = {};
eatWhitespace(inputString);
if (!inputString.length) {
return token;
}
if (isNumber(inputString[0])) {
String start = inputString;
advance(inputString);
while (isNumber(inputString[0])) {
advance(inputString);
}
if (inputString[0] == '.') {
token.kind = KOMMA;
advance(inputString);
while (isNumber(inputString[0])) {
advance(inputString);
}
start.length = inputString.data - start.data;
token.floatValue = parseFloat(start);
} else {
start.length = inputString.data - start.data;
token.kind = INTEGER;
token.intValue = parseInteger(start);
}
//Token für mathematische Operatoren
//ergänzt werden müssen: "atan2"
} else if (inputString[0] == '+') {
token.kind = PLUS;
advance(inputString);
} else if (inputString[0] == '-') {
token.kind = MINUS;
advance(inputString);
} else if (inputString[0] == '*') {
token.kind = MUL;
advance(inputString);
} else if (inputString[0] == '/') {
token.kind = DIV;
advance(inputString);
} else if (inputString[0] == '%') {
token.kind = MODULO;
advance(inputString);
} else if (inputString[0] == '(') {
token.kind = LPAREN;
advance(inputString);
} else if (inputString[0] == ')') {
token.kind = RPAREN;
advance(inputString);
} else if (inputString[0] == '^') {
token.kind = POW;
advance(inputString);
} else if (starts_with(inputString, "atan2"_str)) {
token.kind = ATAN2;
advance(inputString, 5);
} else if (starts_with(inputString, "atan"_str)) {
token.kind = ATAN;
advance(inputString, 4);
} else if (starts_with(inputString, "sqrt"_str)) {
token.kind = SQRT;
advance(inputString, 4);
} else if (starts_with(inputString, "sin"_str)) {
token.kind = SIN;
advance(inputString, 3);
} else if (starts_with(inputString, "cos"_str)) {
token.kind = COS;
advance(inputString, 3);
} else if (starts_with(inputString, "tan"_str)) {
token.kind = TAN;
advance(inputString, 3);
} else if (starts_with(inputString, "ans"_str)) {
token.kind = ANS;
advance(inputString, 3);
}
return token;
}
double parseExpression(String &string);
Token token = {};
double ans = 0;
jmp_buf Rechner;
#define expect(k) if(token.kind != (k)) { printf("Unexpected Token"); exit(0); } token = getNextToken(input);
double parseExpressionOperand(String& input) {
if (token.kind == INTEGER) {
long value = token.intValue;
token = getNextToken(input);
return value;
} else if (token.kind == KOMMA) {
double value = token.floatValue;
token = getNextToken(input);
return value;
} else if (token.kind == LPAREN) {
token = getNextToken(input);
double expression = parseExpression(input);
expect(RPAREN);
return expression;
} else if (token.kind == SQRT) {
token = getNextToken(input);
return sqrt(parseExpressionOperand(input));
} else if (token.kind == SIN) {
token = getNextToken(input);
return sin(parseExpressionOperand(input));
} else if (token.kind == COS) {
token = getNextToken(input);
return cos(parseExpressionOperand(input));
} else if (token.kind == TAN) {
token = getNextToken(input);
return tan(parseExpressionOperand(input));
} else if (token.kind == ATAN) {
token = getNextToken(input);
return atan(parseExpressionOperand(input));
} else if (token.kind == ATAN2) {
printf("Coming soon!");
return 0;
} else if (token.kind == ANS) {
token = getNextToken(input);
return ans;
}
printf("Unexpected Token.\n");
longjmp(Rechner, 0);
return 0;
}
double parseExpressionUnary(String& input) {
if (token.kind == MINUS) {
token = getNextToken(input);
return -parseExpressionUnary(input);
}
return parseExpressionOperand(input);
}
double parseExpressionPower(String& input) {
double expression = parseExpressionUnary(input);
while (token.kind == POW) {
token = getNextToken(input);
expression = pow(expression, parseExpressionUnary(input));
}
return expression;
}
double parseExpressionMultiplicative(String& input) {
double expression = parseExpressionPower(input);
while (token.kind == MUL || token.kind == DIV) {
if (token.kind == MUL) {
token = getNextToken(input);
expression = expression * parseExpressionPower(input);
} else if (token.kind == DIV) {
token = getNextToken(input);
expression = expression / parseExpressionPower(input);
}
}
return expression;
}
double parseExpressionAdditive(String& input) {
double expression = parseExpressionMultiplicative(input);
while (token.kind == PLUS || token.kind == MINUS) {
if (token.kind == PLUS) {
token = getNextToken(input);
expression = expression + parseExpressionMultiplicative(input);
} else if (token.kind == MINUS) {
token = getNextToken(input);
expression = expression - parseExpressionMultiplicative(input);
}
}
return expression;
}
double parseExpression(String &input) {
return parseExpressionAdditive(input);
}
void write_entire_file(const char* filename, String s){
FILE* file = fopen(filename, "w");
fwrite(s.data, s.length, 1, file);
fclose(file);
}
String helpstring = R"(
Taschenrechner --- Help
Operator:
- Addition 'Ausdruck' + 'Ausdruck'
- Subtraktion 'Ausdruck' - 'Ausdruck'
- Multiplikation 'Ausdruck' * 'Ausdruck'
- Division 'Ausdruck' / 'Ausdruck'
- Potenzen 'Ausdruck' ^ 'Ausdruck'
Klammern:
('Ausdruck' + 'Ausdruck') * 'Ausdruck'
('Ausdruck' + 'Ausdruck') * ('Ausdruck' - 'Ausdruck')
'Ausdruck' - (('Ausdruck' + 'Ausdruck') * 'Ausdruck') / 'Ausdruck'
Trigonometrie:
- Wurzel sqrt 'Ausdruck' ODER sqrt('Ausdruck')
- Sinus/Cosinus/Tangens sin/cos/tan 'Ausdruck' ODER sin('Ausdruck')
Letzte Antwort kann mittels 'ans' genutzt werden. Beispiel:
- 4 + 5
9
- ans * 2
18
)"_str;
int main() {
SetConsoleOutputCP(65001);
write_entire_file("Help.txt", helpstring);
while (true) {
setjmp(Rechner);
printf("Was möchten Sie berechnen? Für Hilfe 'help' eingeben!\n");
char buffer[1024];
String input = { 1024, buffer };
fgets(buffer, 1024, stdin);
input.length = strlen(buffer);
if (starts_with(input, "help"_str) || starts_with(input, "Help"_str)) {
printf("%s", helpstring.data);
continue;
}
token = getNextToken(input);
ans = parseExpression(input);
printf("%g\n", ans);
}
return 0;
}