Zahl und Operator Erkenner



  • Ich brauche eine Funktion oder irgendetwas nützliches mit dem ich einen String auf bestimmte Zeichen und Zahlen prüfen kann etwa nach folgendem Schema (Null ist dabei immer der Anfangswert):

    Mögliche Benutzereingabe: +45+3

    + - plus ist ein Operator 0 + ...
    45 - ist eine Zahl d. h. 0 + 45
    + - plus ist ein operator d. h. 45 + ...

    usw.

    Wenn die "Erkennungsmethode" klappen sollte, dann müsste es mit switch und Co. funktionieren. Mir ist auch klar, dass falls ich einen Taschenrechner mit der Hilfe von Strings programmiere, muss ich auch die Vorfahrtsregeln mit beachten etc.

    Greetz, bashzeronine



  • Schon den Parser von Prof. Dankert gelesen?



  • volkard schrieb:

    Schon den Parser von Prof. Dankert gelesen?

    google spuckt http://www.rzbt.haw-hamburg.de/dnksoft/cammpus/parser.html aus.
    Soll ich jetzt die Quellcodes analysieren?



  • bashzeronine schrieb:

    Soll ich jetzt die Quellcodes analysieren?

    Sollen wir das lieber für dich machen?



  • _matze schrieb:

    bashzeronine schrieb:

    Soll ich jetzt die Quellcodes analysieren?

    Sollen wir das lieber für dich machen?

    Du solltest dir vielleicht was eigenes überlegen,
    oder die Dokumentation lesen.



  • Und wo ist die Dokumentation zu finden?



  • Außerdem bat ich um eine oder mehrere geeignete Funktionen, mit dem ich z. B. Stringstellen vergleichen kann etc.



  • Außerdem bat ich um eine oder mehrere geeignete Funktionen, mit dem ich z. B. Stringstellen vergleichen kann etc.

    Und ich bitte dich:

    Erstens darum das du mal die augen aufmachst und selbst guckst
    und zweitens das du dir erstmal selbst gedanken machst und mal etwas ausprobierst.



  • Ich empfehle da ja immer flex und bison mit einem umfangreichen Tutorial und vielen Beispielen ...



  • volkard schrieb:

    Schon den Parser von Prof. Dankert gelesen?

    knivil schrieb:

    Ich empfehle da ja immer flex und bison mit einem umfangreichen Tutorial und vielen Beispielen ...

    das ist doch alles masslos übertrieben.
    @bashzeronine: hier ist was einfacheres: http://gd.tuwien.ac.at/languages/c/cref-mleslie/CONTRIB/SNIP/eval.c
    🙂



  • Außerdem bat ich um eine oder mehrere geeignete Funktionen, mit dem ich z. B. Stringstellen vergleichen kann etc.

    Das geht mit man: strcmp und man: memcmp.



  • Rekursiv kann man die verschachtelten Klammern auflösen:

    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <time.h>
    #include <ctype.h>
    
    static char* s = NULL;
    
    #define NAMELEN_MAX 16
    
    #define isop(x) x == '*' || x == '/' || x == ':' || x == '^'
    #define issig(x) x == '+' || x == '-' 
    #define isval(x) x >= '0' && x <= '9' || x == '.'
    #define iscomma(x) x == ','
    #define isname(x) x >= 'a' && x <= 'z' || x >= 'A' && x <= 'Z' || x == '_'
    #define namechar(x) isname(x) || x >= '0' && x <= '9'
    
    #define isop_rightassociative(x) x == '^'
    
    typedef struct
    {
    	char	fname[NAMELEN_MAX+1];
    	double (*pf) (double);
    }Function;
    
    Function functions[]= {
    {	"abs",   fabs	}, 
    {	"acos",  acos	}, 
    {	"asin",  asin	}, 
    {	"atan",	 atan	}, 
    {	"cos",	 cos	}, 
    {	"cosh",	 cosh	}, 
    {	"exp",	 exp	}, 
    {	"log",	 log	}, 
    {	"log10", log10  }, 
    {	"sin",	 sin	}, 
    {	"sinh",	 sinh	}, 
    {	"sqrt",	 sqrt	}, 
    {	"tan",	 tan	}, 
    {	"tanh",	 tanh	} };
    
    double parse ();
    double parse_operator (double lv, char op);
    
    Function* function_ptr ( char* fname )
    {
    	int first = 0;
    	int last = sizeof(functions)/sizeof(*functions) -1;
    	int i = 0;
    	int cmp = 0;
    
    	while( first <= last )
    	{
    		i = ( first + last )/2;
    		cmp = strcmp(fname, functions[i].fname );
    		if ( cmp < 0 )	last = i-1;
    		else if ( cmp > 0 ) first = i+1;
    		else
    		{
    			return  &functions[i];
    		}
    	}
    	printf ("%s not found.\n", fname );
    	return 0;
    }
    
    int function_name (char* buf, int size)
    {
    	int imax = size-1, i = 0;
    	memset(buf, 0, size);
    
    	while ( i <= imax && namechar(*s) )
    		buf[i++] = *s++;
    
    	if ( namechar(*s) )
    	{
    		printf ("function_name: expression too long, "
    			"started with %s\n", buf);
    		return 1;
    	}
    	return 0;
    }
    
    double value ()
    {
    	char* stopstr = NULL;
    	double value = strtod( s, &stopstr );
    
    	if ( stopstr == s ) 
    	{
    		printf("Syntax error: %s\n", s );
    		exit(1);
    	}
    	s = stopstr;
    	return value;
    }
    
    int sigval (char c)
    {
    	if (c=='+')
    		return 1;
    	else
    		return -1;
    }
    
    double do_function ()
    {
    	Function* fptr = NULL;
    	double value = 0.0;
    	char fname [NAMELEN_MAX+1] = {0};
    
    	if ( function_name(fname, sizeof(fname)))
    		exit(1);
    	if ( NULL == (fptr = function_ptr(fname)))
    		exit(1);
    
    	while(isspace(*s))
    		s++;
    
    	if (*s != '(')
    	{
    		printf ("do_function: '(' expected.\n");
    		exit(1);
    	}
    	else
    	{
    		value = parse();
    	}
    
    	return fptr->pf(value);
    }
    
    double do_operation ( double lv, char op, double rv )
    {
    	switch(op)
    	{
    		case '+':
    			lv = lv + rv;
    		break;
    
    		case '-':
    			lv = lv - rv;
    		break;
    
    		case '/':
    			lv = lv/rv;
    		break;
    
    		case ':':
    			lv = lv/rv;
    		break;
    
    		case '^':
    			lv = pow(lv,rv);
    		break;
    
    		case '*':
    			lv = lv * rv;
    		break;
    
    		default:
    			printf( "Unknown operator: %c\n", op );
    			exit(1);
    	}
    	return lv;
    }
    
    int priority ( char op )
    {
    	int priority = -1;
    	switch(op)
    	{
    		case '+':
    			priority = 1;
    		break;
    
    		case '-':
    			priority = 1;
    		break;
    
    		case '*':
    			priority = 2;
    		break;
    
    		case '/':
    			priority = 2;
    		break;
    
    		case ':':
    			priority = 2;
    		break;
    
    		case '^':
    			priority = 3;
    		break;
    
    		default:
    			printf( "Unknown operator: %c\n", op );
    			exit(1);
    	}
    
    	return priority;
    }
    
    double check_op (char op, char nop, double lv, double rv)
    {
    	if( priority(op) >= priority(nop)
    		&& !(op == nop && isop_rightassociative(op)))
    	{
    		lv = do_operation (lv, op, rv);
    	}
    	else
    	{
    		rv = parse_operator(rv, nop);
    		lv = do_operation (lv, op, rv);	
    	}
    	return lv;
    }
    
    double parse_operator (double lv, char op)
    {
    	char nop = 0, r = 0; // Flags.
    	double rv = 0.0;
    
    	while (*s)
    	{
    		if (isspace(*s))
    		{
    			s++;
    			continue;
    		}
    
    		if (*s == '(')
    		{
    			s++;
    			rv = parse();
    			r = 1;
    			s++;
    			continue;
    		}
    
    		if (isval(*s))
    		{
    			rv = value();
    			r = 1;
    			continue;
    		}
    
    		if (isname(*s))
    		{
    		   rv = do_function();
    		   r = 1;
    		   continue;
    		}
    
    		if (issig(*s))
    		{
    			if (!r)
    			{
    				rv = sigval(*s);
    				r = 1;
    				nop = '*';
    			}
    			else
    			{
    				nop = *s;
    			}
    		}
    
    		if (op && nop)
    		{
    			lv = check_op (op,nop,lv,rv);
    			op = nop;
    			nop = r = 0;
    		}
    		s++;
    	} // while(s)
    
    	if (r)
    		lv = do_operation ( lv, op, rv );
    	return lv;
    }
    
    double parse ()
    {
    	double lv=0.0, rv=0.0; 
    	char op = 0, nop = 0,
    		l = 0, r = 0; // Flags.
    
    	while (*s)
    	{
    		if (isspace(*s))
    		{	
    			s++;
    			continue;
    		}
    
    		if ( *s == ')' )
    			break;
    
    		if ( *s == '(' )
    		{
    			s++;
    			if (!l)
    			{
    				lv = parse();
    				l = 1;
    			}
    			else
    			{
    				rv = parse();
    				r = 1;
    			}
    			s++;
    			continue;
    		}
    
    		if (isval(*s))
    		{
    		  if (!l) 
    		  {
    			  lv = value();
    			  l = 1;
    		  }
    		  else
    		  {
    			  rv = value();
    			  r = 1;
    		  }
    		  continue;
    		}
    
    		if (isname(*s))
    		{
    		  if (!l) 
    		  {
    			  lv = do_function();
    			  l = 1;
    		  }
    		  else
    		  {
    			  rv = do_function();
    			  r = 1;
    		  }
    		  continue;
    		}
    
    		if (issig(*s))
    		{
    			if (!l)
    			{
    				lv = sigval(*s);
    				l = 1;
    				op = '*';
    				s++;
    				continue;
    			}
    
    			if (!op)
    			{
    				op = *s;
    				s++;
    				continue;
    			}
    
    			if (!r)
    			{
    				rv = sigval(*s);
    				r = 1;
    				nop = '*';
    			}
    			else
    			{
    				nop = *s;
    			}
    		}
    
    		if (isop(*s))
    		{
    			if(!op)
    				op = *s;
    			else
    				nop = *s;
    		}
    
    		if (op && nop)
    		{
    			lv = check_op (op,nop,lv,rv);
    			op = nop;
    			nop = r = 0;
    		}
    		s++;
    	} // while(s)
    	if (r)
    		lv = do_operation ( lv, op, rv );
    	return lv;
    }
    
    double evaluate (char* expr)
    {
    	s = expr;
    	return parse();
    }
    
    int main (void)
    {
    	double value;
    	char* s;
    
    	s = "10 ^ cos ( 1 )";
    	value = evaluate (s);
    	printf("%lf\n", value);
    
    	s = "1*(1*(1*(1*(1)*1)*1)*1)*1";
    	value = evaluate (s);
    	printf("%lf\n", value);
    
    	s = "2^1^2";
    	value = evaluate (s);
    	printf("%lf\n", value);
    
    	s = "2*(3*(4*(1+1)))";
    	value = evaluate (s);
    	printf("%lf\n", value);
    
    	s = "((((1)*1)*1)*1)";
    	value = evaluate (s);
    	printf("%lf\n", value);
    
    	s = " 10 ^ ( 1.1 + .9 )";
    	value = evaluate (s);
    	printf("%lf\n", value);
    
    	return 0;
    }
    

    Hier müsste man noch einen Syntaxcheck vorschalten.
    Gruß,
    B.B.



  • Hier müsste man noch einen Syntaxcheck vorschalten.

    Das müsste man erst mal lesen...


Anmelden zum Antworten