Ich hab mir einen Parser gebastelt, der mir einfach Terme löst und das Ergebniss zurückgibt. Das ganze habe ich mit C / C++ gemacht, ich bin aber gezwungen das ganze in reinen C - Code umzuwandeln.
Ich habe mich auch schon versucht, aber da ich wirklich extrem wenig und ungern Elemente aus C verwende bin ich gescheitert.
Hier mein C/C++ Code:
Und hier der Versuch von mir in C-Code (Von der alten Version):
Edit:
Ich habe den Code jetzt auskommentiert und hier nocheinmal ein "Anwendungsbeispiel":
Falls jemand einen kostenlosen Opensource-C-Parser hat, dann kann er ihn mir auch schicken. ;)
Ich habe mich auch schon versucht, aber da ich wirklich extrem wenig und ungern Elemente aus C verwende bin ich gescheitert.
Hier mein C/C++ Code:
PHP Code:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <sstream>
#include <math.h>
using namespace std;
double Calculate(string str)
{
int size=str.length();
string calcs[str.length()*2];
bool operat=0;
int number=0;
while (1)
{
cout<<str<<"\n";
////// Resetten der Variablen Start //////
number=0;
operat=0;
////// Resetten der Variablen Ende //////
for (int i=0; i<str.length(); i++) // Die Schleife durchläuft den kompletten Eingabe-String
{
if ((str[i]>47 && str[i]<58) || str[i]==46)
// Wenn ein Zeichen zwischen AscII-Code 48 (=0) und 57 (=9) oder wenn ein Punkt (. für Komma) gefunden wurde
// Dann gehört das zu einer Zahl und bekommt einen extra Platz in calcs[]
{
calcs[number]+=str[i]; // Die Zahl bekommt einen Platz in dem Array calcs[]
operat=0; // Die Zahl ist kein Operator (+-*/^) , also setzen wir operat zu 0
}
else if ( (str[i]>39 && str[i]<44) || str[i]==94 || str[i]==47 ||str[i]==45 )
// Wenn einer der Operatoren ()*+^/- gefunden wurde, dann ist die Bedingung wahr
{
if ((operat==1 || i==0) && (str[i]==45 || str[i]==43) )
// Wenn wir schoneinmal einen Operator gefunden haben oder wenn wir das
// erste Zeichen in dem String überprüfen und wir einen Plus oder Minus Operator finden
// dann muss der + bzw. - Operator zu einer Zahl gehören, z.b.
// -12+-2
// bzw. 12--3
{
calcs[number]+=str[i]; // Unser Zeichen bekommt also den selben Platz wie unsere Zahl
}
else // Ansonsten wenn der Operator nicht zu einer Zahl gehört
{
number++; // Unser Operator bekommt den nächsten Platz in calcs
calcs[number]+=str[i];
number++; // Der Operator steht alleine in calcs[number], es wird also gleich ein Schritt weitergezählt
operat=1; // Wir haben einen Operator gefunden
}
}
}
str="";
for (int i=0; i<number; i++) // Eine Schleife, die durch alle unsere Operatoren/Zahlen läuft
{
if ((calcs[i][0]>47 && calcs[i][0]<58)||(calcs[i][1]>47 && calcs[i][1]<58))
// Wenn wir an diesem Platz des Arrays calcs eine Zahl haben, dann ist die Bedingung wahr
// Wir überprüfen ob wir eine Zahl haben, indem wir uns nur das erste Zeichen anschauen
// wenn das erste Zeichen eine Zahl ist, dann ist alles eine Zahl
// Falls das erste Zeichen keine Zahl ist, kann es immernoch sein, dass wir es mit
// einer vorzeichenbehafteten Zahl zu tun haben (z.b. -44)
// Also müssen wir auch noch das 2. Zeichen überprüfen
{
if (calcs[i+1]=="^" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)))
// calcs[i] muss eine Zahl sein und calcs[i+2] muss eine Zahl sein
// Damit wir wissen was wir mit den beiden Zahlen machen müssen,
// schauen wir uns an was calcs[i+1] ist.
// Ist calcs[i+1] also ^ und calcs[i] eine Zahl und calcs[i+2] auch eine Zahl,
// Dann können wir ruhig den Code ausführen lassen
// Wir lassen ^ zuerst überprüfen, da ^ die höchste Priorität hat.
// danach kommt */ und dann +-
{
calcs[i]=NumberToString(pow(StringToNumber(calcs[i]),StringToNumber(calcs[i+2])));
calcs[i+2]=""; // Reset der Zahl, da wir sie schoneinmal verrechnet haben
calcs[i+1]=""; // Reset der Zahl, da wir sie schoneinmal verrechnet haben
break; // Wir dürfen immer nur eine Operation pro Durchgang machen (eventuel sind nach dieser
// einen Operation Klammern verschwunden und wir müssen das was zwischen den Klammern
// steht immer zuerst ausrechnen
}
else if (calcs[i+1]=="*" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="^")
// Wenn wir also kein ^ gefunden haben, sondern ein *
{
calcs[i]=NumberToString(StringToNumber(calcs[i])*StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
else if (calcs[i+1]=="/" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="^")
// Dasselbe wie oben nur mit /
{
calcs[i]=NumberToString(StringToNumber(calcs[i])/StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
else if (calcs[i+1]=="+" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="*" && calcs[i+3]!="/" && calcs[i+3]!="^")
// Dasselbe wie oben nur mit +
{
calcs[i]=NumberToString(StringToNumber(calcs[i])+StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
else if (calcs[i+1]=="-" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="*" && calcs[i+3]!="/" && calcs[i+3]!="^")
// Dasselbe wie oben nur mit -
{
calcs[i]=NumberToString(StringToNumber(calcs[i])-StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
}
else if(calcs[i]=="(")
// Wir haben also an der Stelle calcs[i] keine Zahl, sondern eine geöffnete Klammer
{
if (((calcs[i+1][0]>47 && calcs[i+1][0]<58) || (calcs[i+1][1]>47 && calcs[i+1][1]<58)) && calcs[i+2]==")")
// Wenn calcs[i+1] eine Zahl ist, dann sollten wir einmal überprüfen ob calcs[i+2] eine geschlossene Klammer ist
// und ob zwischen der geöffneten Klammer (calcs[i]) und der Geschlossenen (calcs[i+2]) eine zahl ist,
// Wenn dort nur eine Zahl ist, dann können wir die Klammern entfernen
{
calcs[i+2]=""; // Klammern werden entfernt
calcs[i]=""; // Klammern werden entfernt
break; // Wie immer darf alles nur einmal durchlaufen werden
}
}
}
for (int i=0; i<=number; i++)
{
str+=calcs[i]; // Es wird ein neuer Term gebildet, aus den vorhandenen
calcs[i]=""; // Resetten des Inhalts
}
if (number<=2) break; // Wenn wir 2 oder weniger Nummern gefunden haben, dann wird unsere Schleife verlassen
// Bei 2 Nummern reicht ein Durchgang und deswegen kann danach verlassen werden
}
return StringToNumber(str); // returnt das Ergebniss
}
double StringToNumber(string str)
{
stringstream Str;
Str << str;
double d;
Str >> d;
return d;
}
string NumberToString(double d)
{
ostringstream Str;
Str << d;
string ZahlAlsString(Str.str());
return ZahlAlsString;
}
PHP Code:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
double Calculate(char* str)
{
unsigned char count=0;
char calcs[10][11];
bool operat=0;
unsigned char number=0;
for (short i=0;i<sizeof(str);i++)
{
if ((str[i]>47 && str[i]<58) || str[i]==46)
{
calcs[number][count]=str[i];
count++;
}
else if ( (str[i]>39 && str[i]<44) || str[i]==94 || str[i]==47 ||str[i]==45 )
{
if ((operat==1 || i==0) && (str[i]==45 || str[i]==43) )
{
calcs[number][count]=str[i];
count++;
}
else
{
number++;
count=0;
calcs[number][count]=str[i];
number++;
count=0;
operat=1;
}
}
}
str="";
for (unsigned char i=0;i<number;i++)
{
if ((calcs[i][0]>47 && calcs[i][0]<58)||(calcs[i][1]>47 && calcs[i][1]<58))
{
if (calcs[i+1][0]=='^' && calcs[i+1][1]==NULL && calcs[i+2][0]!=NULL && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)))
{
NumberToString(pow(StringToNumber(calcs[i]),StringToNumber(calcs[i+2])),calcs[i]);
//calcs[i+2]="";
for (char ii=0;ii<10;ii++)
{
calcs[i+1][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
else if (calcs[i+1][0]=='*' && calcs[i+1][1]==NULL && calcs[i+2][0]!=NULL && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="^")
{
NumberToString(StringToNumber(calcs[i])*StringToNumber(calcs[i+2]),calcs[i]);
for (char ii=0;ii<10;ii++)
{
calcs[i+1][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
else if (calcs[i+1][0]=='/' && calcs[i+1][1]==NULL && calcs[i+2][0]!=NULL && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="^")
{
NumberToString(StringToNumber(calcs[i])/StringToNumber(calcs[i+2]),calcs[i]);
for (char ii=0;ii<10;ii++)
{
calcs[i+1][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
else if (calcs[i+1][0]=='+' && calcs[i+1][1]==NULL && calcs[i+2][0]!=NULL && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="*" && calcs[i+3]!="/" && calcs[i+3]!="^")
{
NumberToString(StringToNumber(calcs[i])+StringToNumber(calcs[i+2]),calcs[i]);
for (char ii=0;ii<10;ii++)
{
calcs[i+1][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
else if (calcs[i+1][0]=='-' && calcs[i+1][1]==NULL && calcs[i+2][0]!=NULL && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="*" && calcs[i+3]!="/" && calcs[i+3]!="^")
{
NumberToString(StringToNumber(calcs[i])-StringToNumber(calcs[i+2]),calcs[i]);
//cout<<calcs[i];
for (char ii=0;ii<10;ii++)
{
calcs[i+1][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
}
else if(calcs[i][0]=='(')
{
if (((calcs[i+1][0]>47 && calcs[i+1][0]<58) || (calcs[i+1][1]>47 && calcs[i+1][1]<58)) && calcs[i+2]==")")
{
for (char ii=0;ii<10;ii++)
{
calcs[i][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
else if ((((calcs[i+1][0]=='+' && calcs[i+1][1]==NULL) || (calcs[i+1][0]=='-' && calcs[i+1][1]==NULL)) && calcs[i+1][1]>47 && calcs[i+1][1]<58) || (calcs[i+1][0]>47 && calcs[i+1][0]<58) && calcs[i+2][0]==')')
{
for (char ii=0;ii<10;ii++)
{
calcs[i][ii]='"';
calcs[i+2][ii]='"';
}
break;
}
}
}
cout<<sizeof(str)<<"\n";
unsigned char ai=0;
for (unsigned char i=0;i<=number;i++)
{
for (unsigned char ii=0;ii<10;ii++)
{
cout<<calcs[i][ii]<<" ";
if (calcs[i][ii]!='"')
{
//cout<<"!"<<str[ai];
//str[ai]=calcs[i][ii];
//cout<<"!";
ai++;
}
else break;
}
}
cout<<2;
cout<<str;
if (number>2) Calculate(str);
return StringToNumber(str);
}
double StringToNumber(char* str)
{
return atof(str);
}
void NumberToString(double i,char* buffer)
{
sprintf(buffer, "%f", i);
}
Ich habe den Code jetzt auskommentiert und hier nocheinmal ein "Anwendungsbeispiel":
PHP Code:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <sstream>
#include <math.h>
using namespace std;
double Calculate(string str);
double StringToNumber(string str);
string NumberToString(double d);
int main()
{
cout<<Calculate("(2*3)+4*2+(2*10+8)*(2-2)-2+5");
}
double Calculate(string str)
{
int size=str.length();
string calcs[str.length()*2];
bool operat=0;
int number=0;
while (1)
{
cout<<str<<"\n";
////// Resetten der Variablen Start //////
number=0;
operat=0;
////// Resetten der Variablen Ende //////
for (int i=0; i<str.length(); i++) // Die Schleife durchläuft den kompletten Eingabe-String
{
if ((str[i]>47 && str[i]<58) || str[i]==46)
// Wenn ein Zeichen zwischen AscII-Code 48 (=0) und 57 (=9) oder wenn ein Punkt (. für Komma) gefunden wurde
// Dann gehört das zu einer Zahl und bekommt einen extra Platz in calcs[]
{
calcs[number]+=str[i]; // Die Zahl bekommt einen Platz in dem Array calcs[]
operat=0; // Die Zahl ist kein Operator (+-*/^) , also setzen wir operat zu 0
}
else if ( (str[i]>39 && str[i]<44) || str[i]==94 || str[i]==47 ||str[i]==45 )
// Wenn einer der Operatoren ()*+^/- gefunden wurde, dann ist die Bedingung wahr
{
if ((operat==1 || i==0) && (str[i]==45 || str[i]==43) )
// Wenn wir schoneinmal einen Operator gefunden haben oder wenn wir das
// erste Zeichen in dem String überprüfen und wir einen Plus oder Minus Operator finden
// dann muss der + bzw. - Operator zu einer Zahl gehören, z.b.
// -12+-2
// bzw. 12--3
{
calcs[number]+=str[i]; // Unser Zeichen bekommt also den selben Platz wie unsere Zahl
}
else // Ansonsten wenn der Operator nicht zu einer Zahl gehört
{
number++; // Unser Operator bekommt den nächsten Platz in calcs
calcs[number]+=str[i];
number++; // Der Operator steht alleine in calcs[number], es wird also gleich ein Schritt weitergezählt
operat=1; // Wir haben einen Operator gefunden
}
}
}
str="";
for (int i=0; i<number; i++) // Eine Schleife, die durch alle unsere Operatoren/Zahlen läuft
{
if ((calcs[i][0]>47 && calcs[i][0]<58)||(calcs[i][1]>47 && calcs[i][1]<58))
// Wenn wir an diesem Platz des Arrays calcs eine Zahl haben, dann ist die Bedingung wahr
// Wir überprüfen ob wir eine Zahl haben, indem wir uns nur das erste Zeichen anschauen
// wenn das erste Zeichen eine Zahl ist, dann ist alles eine Zahl
// Falls das erste Zeichen keine Zahl ist, kann es immernoch sein, dass wir es mit
// einer vorzeichenbehafteten Zahl zu tun haben (z.b. -44)
// Also müssen wir auch noch das 2. Zeichen überprüfen
{
if (calcs[i+1]=="^" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)))
// calcs[i] muss eine Zahl sein und calcs[i+2] muss eine Zahl sein
// Damit wir wissen was wir mit den beiden Zahlen machen müssen,
// schauen wir uns an was calcs[i+1] ist.
// Ist calcs[i+1] also ^ und calcs[i] eine Zahl und calcs[i+2] auch eine Zahl,
// Dann können wir ruhig den Code ausführen lassen
// Wir lassen ^ zuerst überprüfen, da ^ die höchste Priorität hat.
// danach kommt */ und dann +-
{
calcs[i]=NumberToString(pow(StringToNumber(calcs[i]),StringToNumber(calcs[i+2])));
calcs[i+2]=""; // Reset der Zahl, da wir sie schoneinmal verrechnet haben
calcs[i+1]=""; // Reset der Zahl, da wir sie schoneinmal verrechnet haben
break; // Wir dürfen immer nur eine Operation pro Durchgang machen (eventuel sind nach dieser
// einen Operation Klammern verschwunden und wir müssen das was zwischen den Klammern
// steht immer zuerst ausrechnen
}
else if (calcs[i+1]=="*" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="^")
// Wenn wir also kein ^ gefunden haben, sondern ein *
{
calcs[i]=NumberToString(StringToNumber(calcs[i])*StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
else if (calcs[i+1]=="/" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="^")
// Dasselbe wie oben nur mit /
{
calcs[i]=NumberToString(StringToNumber(calcs[i])/StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
else if (calcs[i+1]=="+" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="*" && calcs[i+3]!="/" && calcs[i+3]!="^")
// Dasselbe wie oben nur mit +
{
calcs[i]=NumberToString(StringToNumber(calcs[i])+StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
else if (calcs[i+1]=="-" && calcs[i+2]!="" && ((calcs[i+2][0]>47 && calcs[i+2][0]<58)||(calcs[i+2][1]>47 && calcs[i+2][1]<58)) && calcs[i+3]!="*" && calcs[i+3]!="/" && calcs[i+3]!="^")
// Dasselbe wie oben nur mit -
{
calcs[i]=NumberToString(StringToNumber(calcs[i])-StringToNumber(calcs[i+2]));
calcs[i+2]="";
calcs[i+1]="";
break;
}
}
else if(calcs[i]=="(")
// Wir haben also an der Stelle calcs[i] keine Zahl, sondern eine geöffnete Klammer
{
if (((calcs[i+1][0]>47 && calcs[i+1][0]<58) || (calcs[i+1][1]>47 && calcs[i+1][1]<58)) && calcs[i+2]==")")
// Wenn calcs[i+1] eine Zahl ist, dann sollten wir einmal überprüfen ob calcs[i+2] eine geschlossene Klammer ist
// und ob zwischen der geöffneten Klammer (calcs[i]) und der Geschlossenen (calcs[i+2]) eine zahl ist,
// Wenn dort nur eine Zahl ist, dann können wir die Klammern entfernen
{
calcs[i+2]=""; // Klammern werden entfernt
calcs[i]=""; // Klammern werden entfernt
break; // Wie immer darf alles nur einmal durchlaufen werden
}
}
}
for (int i=0; i<=number; i++)
{
str+=calcs[i]; // Es wird ein neuer Term gebildet, aus den vorhandenen
calcs[i]=""; // Resetten des Inhalts
}
if (number<=2) break; // Wenn wir 2 oder weniger Nummern gefunden haben, dann wird unsere Schleife verlassen
// Bei 2 Nummern reicht ein Durchgang und deswegen kann danach verlassen werden
}
return StringToNumber(str); // returnt das Ergebniss
}
double StringToNumber(string str)
{
stringstream Str;
Str << str;
double d;
Str >> d;
return d;
}
string NumberToString(double d)
{
ostringstream Str;
Str << d;
string ZahlAlsString(Str.str());
return ZahlAlsString;
}