316 lines
7.8 KiB
C++
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;
|
|
} |