Formel in zeichenkette einlesen und bearbeiten / auflösen





  • Hallo,

    ja dazu braucht es einen Parser bzw. Scanner, der deine Formelsprache analysiert und dann auswertet. Erstmal musst du die einzelnen Tokens deiner dort definierten Sprache erkennen und dann entsprechend Parsen. Wichtig dabei ist die Beachtung der Punkt-vor-Strich-Rechnung und Evaluierung von Sub-Ausdrücken.

    Als Beispiel hier mal der Sourcecode eines einfachen Infix-to-Postfix Compilers. Jedes Symbol dieser Sprache besteht aus einem Zeichen - damit entfällt das Scannen quasi gänzlich, und wird von der Funktion match() übernommen.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    /*
    	Sprachdefinition:
    
    	expr = expr + term		"+"
    	expr = expr - term		"-"
    	expr = term
    	term = 0			"0"
    	term = 1			"1"
    	term = 2			"2"
    	term = 3			"3"
    	term = 4			"4"
    	term = 5			"5"
    	term = 6			"6"
    	term = 7			"7"
    	term = 8			"8"
    	term = 9			"9"
    */
    
    char	lookahead;
    int		pos = 0;
    char	expression[20+1];
    
    void error()
    {
    	printf("Error!\n");
    }
    
    void match( char t )
    {
    	if( lookahead == t )
    	{
    		pos++;
    		lookahead = expression[pos];		
    	}
    	else
    		error();
    }
    
    void term()
    {
    	switch( lookahead )
    	{
    		case '0':
    		case '1':
    		case '2':
    		case '3':
    		case '4':
    		case '5':
    		case '6':
    		case '7':
    		case '8':
    		case '9':
    			printf("%c", lookahead);
    			match( lookahead );
    			break;
    		default:
    			error();
    			break;
    	}
    }
    
    void expr()
    {
    	term();
    	while(true)
    	{
    		switch( lookahead )
    		{
    			case '+':
    				match('+');
    				term();
    
    				printf("+");
    				break;
    			case '-':
    				match('-');
    				term();
    
    				printf("-");
    				break;
    			default:
    				return;
    
    		}
    	}
    }
    
    int main ( int argc, char** argv )
    {
    	strcpy( expression, "9-5+2");
    	lookahead = *expression;
    
    	expr();
    	printf("\n");
    	getchar();
    
    	return 0;
    }
    

    ~code_pilot



  • danke,
    wenn ich das richtig verstanden habe muss ich mir einen eigenen compiler bauen der dann das macht was ein wissenschaftlicher tschenrechner macht und solche formeln wie angegeben ausrechnet bzw. umstellt oder ungleichungen auflöst.

    gibt es denn überhauptkeine möglichkeit einzelne zeichen aus char quest[1025]
    vorher eingegeben mit gets(quest) auszulesen?

    ich kann doch mit strlen die länge des eingegebenen strings bestimmen, dann könnte ich doch mit scanf(quest[2]); so das dritte zeichen der kette auslesen und dann in eine char variable an ps 3 schieben wenn die ersten 3 ziffern dieser kette dann z.B. 835 ist könnte ich dann diesen string mit atoi in einen int verwandeln und dann damit rechnen.

    oder ist diese möglichkeit absolut unmöglich? wenn ja gibt es nicht doch irgendeine andere möglichkeit dieses prob zu lösen ohne gleich informatik zu studieren.



  • Tobias_N schrieb:

    damit kann man doch nur "gramatiken" bearbeiten [...]

    Ein mathematischer Term wird auch nach ganz bestimmten Regeln aufgebaut. Diese kann man durch eine Grammatik beschreiben. Ist also genau das was Du brauchst.

    Schau hier: http://epaperpress.com/lexandyacc/. Das sind Tools die dir helfen werden.



  • @Tobias:

    Ein einfacher Scanner, der Zahlen und Operatoren unterscheiden kann ist folgender (ist jetzt nur nicht mit dynamischer Speicherverwaltung!):

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define NUMBER 0
    #define OPERATOR 1
    
    typedef struct
    {
    	int type;
    	char tok[255];
    	int len;
    } token;
    
    int scan( token* t, char* expression )
    {
    	int i;
    	int tp = 0;
    
    	for( i = 0; i < strlen( expression ); i++ )
    	{
    		switch( expression[i] )
    		{
    			case '0':
    			case '1':
    			case '2':
    			case '3':
    			case '4':
    			case '5':
    			case '6':
    			case '7':
    			case '8':
    			case '9':
    				if( tp > 0 && t[tp-1].type == NUMBER )
    				{
    					t[tp-1].tok[t[tp-1].len] = expression[i];
    					t[tp-1].tok[t[tp-1].len+1] = '\0';
    
    					t[tp-1].len++;
    				}
    				else
    				{
    					t[tp].type = NUMBER;
    
    					t[tp].tok[0] = expression[i];
    					t[tp].tok[1] = '\0';
    
    					t[tp].len = 1;
    
    					tp++;
    				}
    				break;
    			case '+':
    			case '-':
    			case '*':
    			case '/':
    				if( tp > 0 && t[tp-1].type == OPERATOR )
    				{
    					//Weiterer Operator ist nicht erlaubt!
    					printf("Syntaxfehler!\n");
    				}
    				else
    				{
    					t[tp].type = OPERATOR;
    
    					t[tp].tok[0] = expression[i];
    					t[tp].tok[1] = '\0';
    
    					t[tp].len = 1;
    
    					tp++;
    				}
    				break;
    		}
    	}
    
    	return tp;
    } 
    
    int main( int argc, char** argv )
    {
    	char exp[255+1];
    	token tokens[100];
    	int cnt, i;
    
    	printf("Expression: ");
    	gets( exp );
    
    	cnt = scan( tokens, exp );
    
    	printf("\n");
    
    	for( i = 0; i < cnt; i++ )
    	{
    		printf("%s ist vom Typ %d\n", tokens[i].tok, tokens[i].type );
    	}
    
    	//Aber hier wird dann später geparst...
    
    	getchar();
    	return 0;
    }
    

    Anhand der Ausgabe kann man deutlich erkennen, das der Scanner die Tokens korrekt erkannt hat. Nach dem Scan folgt dann das Parsen, wobei der Parser selber seine Tokens immer bei Bedarf durch den Scanner ermitteln kann, d.h. der Parser ermittelt ein Token, entscheidet, was er damit tun soll, und ermittelt dann bei bedarf das nächste Token. Das kann man aber machen wie man lustig ist.

    Testlauf:

    Expression: 123*6+55-3

    123 ist vom Typ 0
    * ist vom Typ 1
    6 ist vom Typ 0
    + ist vom Typ 1
    55 ist vom Typ 0
    - ist vom Typ 1
    3 ist vom Typ 0

    ~cp



  • danke,

    ich kann nur keine gleichungen eingeben à la 3x*2y=7(2+y)²

    mir werden dann die werte zugewiesen, jedoch wird u.a. das gleichheitszeichen einfach missachtet, ich spiele mal ein wenig mit dem code herrum und halte dich auf dem laufenden.

    p.S. hast du eine ahnung wie ich mit pointern einzelne elemente eines char strings auslesen und in variablen speichern kann? ich habe mir gerade eine datei im netz angeschaut und dort wurde mir etwas in dieser richtung erklärt
    (http://www.guardian-online.de/c-kurs/) dann pointer(i)



  • Hallo Tobias,

    ich denke du solltest dafür eher richtig C programmieren lernen bevor du dich solch einer Aufgabe zuwendest.

    Pointer sind eine tolle Sache - wenn man weiss, wie man damit umgeht.

    Du kannst z.B. einen String Zeichenweise so ausgeben:

    char bla[255];
    char* x;
    
    strcpy( bla, "Hello World and everything is fine!");
    for( x = bla; *x != '\0'; x++ )
    {
          printf("Pointer is %c\n", *x);
    }
    

    Das Gleichheitszeichen erkennt der o.g. Scanner auch (noch) nicht. Das muss man erst alles einbauen.

    Gruß
    ~code_pilot



  • ja das habe ich schon einige male gehört, doch wann kann ich sagen das ich c programmieren kann ( deiner definition nach ), ich lese zwar seit einiger zeit haufenweise bücher über diese und andere sprachen, jedoch habe ich (peinlicher-)weise bis dato noch nie den übergang zuum schreiben von programmen gemacht; wusste auch um ehrlich zu sein nicht was ich maches sollte bis wir die lineare algebra und analysis durchnahmen.



  • Tobias_N schrieb:

    ja das habe ich schon einige male gehört, doch wann kann ich sagen das ich c programmieren kann ( deiner definition nach )

    Dann, wenn du dir bei der Umsetzung von Programmen nur noch Gedanken über das Problem selbst machst und NICHT über Details der Sprache (so wie du z.B. bei den Zeigern).
    Du solltest wirklich erst die Sprache verstanden haben, bevor du sowas wie einen Scanner schreibst.



  • Man lernt eine Programmiersprache nicht durch Bücher, sondern durch Praxis. Oder wie sagt man doch gleich: Übung macht den Meister! Und Bücher schmökern ist kein üben, sondern Grundlagen und Theorie. Praxis braucht's!

    Fang vielleicht erstmal mit kleinen Dingen an. Probiere aus, was für tolle Dinge man mit Pointer machen kann. Lerne, Speicher dynamisch zu verwalten. Lerne professionelle Lösungen, Kniffe und Techniken anhand der Sourcecodes anderer oder durch Übung.

    Ich programmiere jetzt seid 4 Jahren in C, insgesamt programmiere ich seit 7 Jahren. Und ich lerne heute noch nicht aus. Und das ist auch der reiz dabei: Neue Dinge erschaffen, neue Dinge enddecken!

    Das macht Spaß! 😃 😃 😃

    ~cp



  • Du kannst C programmieren wenn du keine Fragen mehr dazu hast 😉



  • fluxy schrieb:

    Du kannst C programmieren wenn du keine Fragen mehr dazu hast 😉

    signaturtauglicher satz!


Anmelden zum Antworten