[QUIZ#2] teambeta (C)

Teambeta

Erfahrenes Mitglied
Huhu ich hab heut erst so spät gesehen, das ein 2. Quiz eröffnet wurde und hab schnell was in C gemacht.

Ist noch nicht komplett fertig ( zusätzliche Funktionen wie Wurzel ziehen, etc. ), ich werd es nach Oceans Eleven noch hinzufügen :p

// EDIT: Quellcode weiter unten!
 
Zuletzt bearbeitet:
Sooooo.

Also zum ersten werden die eingegebenen Zeichen überprüft ob es Kommandos oder Funktionen sind und/oder ob es sich um eine Zuweisung handelt.

Danach wird jenachdem ob es Rechnung ist per parse in eine normale Rechnung geformt.

Danach wird das Ergebnis ausgerechnet und der Variable zugewiesen.

Kompiliert wird das ganze mit gcc quiz2.c -lm -o quiz2.

C:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define LINE 256
#define OPER 10
#define NUMS 20
#define EXPR 512
#define KEY_AMNT 27
#define KEY(x) g_aiTable[x][0]
#define VAL(x) g_aiTable[x][1]

/* COMMAND LIST */
#define CMD_LIST ":vars"
#define CMD_CLR  ":clear"
#define CMD_QUIT ":quit"
#define CMD_ASGN ":="

/* CHECK MACROS */
#define IS_OPER(x) 	  (x=='*')\
			||(x=='/')\
			||(x=='+')\
			||(x=='-')\
			||(x=='^')\
			||(x=='%')

#define IS_FUNC(x)	  0==strncmp(x, "log", 3)\
			||0==strncmp(x, "exp", 3)\
			||0==strncmp(x, "cos", 3)\
			||0==strncmp(x, "sin", 3)\
			||0==strncmp(x, "sqrt", 4)\
			||0==strncmp(x, "tan", 3)

typedef enum 
{
	false = 0,
	true,
} bool;

typedef unsigned int ui;

void init( void );
void trim( char* str );
void evaluate( char* str );
void parse( int var, char* calcstr );

bool skip_space( char** str );
bool is_operator( char** str, char* op );

void calc_func( int var, char* str );
bool calc_expr( int var, char* expr, double* val );
double calc( char op, double a, double b );

double g_aiTable[27][2]; // _ and a-z with
bool g_bQuit = false;

int main( void )
{
	char iaCalculation[LINE] = {0};

	init();
	
	while( false == g_bQuit )
	{
		fputs( "> ", stdout );
		memset( iaCalculation, 0x00, LINE );
		fgets( iaCalculation, LINE, stdin );
		trim(iaCalculation);
		evaluate(iaCalculation);
	}

	return 0;
}

void init( void )
{
	ui it = 1;
	
	KEY(0) = '_';
	VAL(0) = 0.0f;
	
	for(;it<(ui)KEY_AMNT; it++)
	{
		KEY(it) = 0x60+it;
		VAL(it) = 0.0f;
	}
}

void trim( char* str )
{
	while( *str != 0x0A ){ str++; };// remove newline
	*str = 0x00;			
	return;
}

void evaluate( char* str )
{
	ui 	it = 0;
	char* temp = NULL;
	ui found = false;
	
	if( !strcmp( CMD_LIST, str ) )	/* list vars? */
	{
		for(;it<(ui)KEY_AMNT; it++)
		{
			if( VAL(it) )
			{
				found = true;
				printf( "%c\t=\t%f\n", (char)KEY(it), VAL(it) );
			}
		}

		if( true != found )
		{
			printf("No Vars found\n");
		}
	}
	else if( !strcmp( CMD_CLR, str ) ) /* clear vars? */
	{
		for(;it<(ui)KEY_AMNT; it++)
                {
                	VAL(it) = 0;
		}

		printf("Vars removed\n");
	}
	else if( !strcmp( CMD_QUIT, str ) ) /* quit application? */
	{
		printf("Byebye.\n");
		g_bQuit = true;
	}
	else if( IS_FUNC(str) ) /* is a func? */
	{
		calc_func(0, str);
	}
	else if( 1 == strlen(str) ) /* is var to print? */
	{
		if( *str == '_' )
		{
			printf("%c = %f\n",(char)KEY(0),VAL(0));
		}
		else if( isalpha(*str) )
		{
			while((*str!=KEY(found)) && (found!=KEY_AMNT))
				found++;

			if( found == KEY_AMNT )
			{
				printf( "Invalid Var\n" );
				return;
			}
			else
			{
				if( !VAL(found) )
				{
					printf( "%c not set.\n", (char)KEY(found) );
					return;
				}

				printf( "%c = %f\n", (char)KEY(found), VAL(found) );
			}
		}
		else
		{
			printf("Invalid Operation\n");
			return;
		}
	}
	else /* is func to assign a var, or just calc with or without assigning to a var */
	{
		if( (temp=strstr(str, CMD_ASGN)) )
		{
			temp = temp+strlen(CMD_ASGN);
			while((*str!=KEY(found)) && (found!=KEY_AMNT))
				found++;

			if( found == KEY_AMNT )
			{
				printf("Invalid Operation\n");
				return;
			}

			if( IS_FUNC(temp) )
			{
				calc_func(found,temp);
				return;
			}
		}
		else
		{
			temp = str;
		}

		parse( found, temp );
	}

	return;
}

bool skip_space( char** str )
{
	if( (**str) == 0x20 )
	{
		*str=*str+1;
		return true;
	}

	return false;
}

bool is_operator( char** str, char *op )
{
	if( IS_OPER(**str) )
	{
		if(NULL!=op) *op = **str;
		*str=*str+1;
		return true;
	}

	return false;
}

void parse( int var, char* calcstr )
{
	char expression[EXPR]  = {0}; ui expr_cnt = 0;
	double expr_val[NUMS] = {0.0f}; ui val_cnt = 0;
	char* check = calcstr; // ptr -> ptr
	char oper[OPER] = {0}; ui oper_cnt = 0;
	bool bvar = false;
	ui found = 0;
	bool op_found = false;
	bool arg1 = false;

	/* string empty? */
	if( !calcstr || !strlen(calcstr) )
	{
		printf("Invalid Operation\n");
		return;
	}

	/* check if operator is inserted */
	while( *check != 0x00 )
	{
		if( IS_OPER(*check) )	{ op_found = true; break; 	}
		else			{ check++;	 		}
	}

	/* no operator inserted, just assign */
	if( !op_found )
	{
		if( isalpha(*calcstr) )
		{
			found = 0;

			while((*calcstr!=(char)KEY(found)) && (found!=KEY_AMNT))
				found++;

			if( found == KEY_AMNT )
			{
				printf("Var not found.");
			}
			
			VAL(0)   = VAL(found);
			VAL(var) = VAL(0);			
		}
		else
		{
			VAL(0)   = atof(calcstr);
			VAL(var) = VAL(0);
		}

		printf ("%c = %f\n", (char)KEY(var), VAL(0));

		return;
	}
	/* calc */
	else
	{
		while( *calcstr != 0x00 )
		{
			if( skip_space( &calcstr ) )
				continue;

			if( is_operator( &calcstr, &oper[oper_cnt] ) )
			{
				oper_cnt++;
				continue;
			}
			
			/* check if char is not a var and not a number */
			if( !isalnum( *calcstr ) && *calcstr != '_' )
			{
				printf("\n%c: Undefiniert.\n", *calcstr);
				return;
			}

			/* getting first operand */
			if( arg1 == false )
			{
				arg1 = true;

				/* a var is used */
				if( isalpha(*calcstr) )
				{
					bvar = true;
					found = 0;

					/* get var number */
					while((*calcstr!=(char)KEY(found)) && (found!=KEY_AMNT))
						found++;

					/* check if found */
					if( found != KEY_AMNT )
					{
						/* var doesnt seem to have a value */
						if( !VAL(found) )
						{
							printf( "Var not set!\n" );
							return;
						}

						/* add to the expression string */
						if( (expr_cnt+2)<EXPR )
						{
							strcat(expression+expr_cnt,"(i");
							expr_cnt += 2;
						}

						/* and add the var value to the value table */
						if( val_cnt<NUMS )
							expr_val[val_cnt++] = VAL(found);
					}
					else
					{
						printf( "Invalid Var\n" );
						return;
					}
				}
				else
				{
					/* same as above */
					if( (expr_cnt+2)<EXPR )
					{
						strcat(expression+expr_cnt,"(i");
						expr_cnt += 2;
					}

					if( val_cnt<NUMS )
							expr_val[val_cnt++] = atof(calcstr);
				}

			}
			/* getting second operand */
			else if( oper_cnt != 0 )
			{
				/* insert the operator to the list */
				if( (expr_cnt+1)<EXPR )
				{
					*(expression+expr_cnt)=oper[oper_cnt-1];
					expr_cnt++;
				}

				oper[--oper_cnt] = 0x00;
				
				/* same as above */
				if( isalpha(*calcstr) )
				{
					bvar = true;
                                        found = 0;

                                        while((*calcstr!=KEY(found)) &&(found!=KEY_AMNT))
				        	found++;

					if( found != KEY_AMNT )
					{
						if( !VAL(found) )
						{
							printf( "Var not set!\n" );
							return;
						}

						if( (expr_cnt+2)<EXPR )
						{
							strcat(expression+expr_cnt,"i)");
							expr_cnt += 2;
						}

						if( val_cnt<NUMS )
							expr_val[val_cnt++] = VAL(found);
					}
                                        else
					{
						printf( "Invalid Var\n" );
						return;
					}
				}
				else
				{
					if( (expr_cnt+2)<EXPR )
					{
						strcat(expression+expr_cnt,"i)");
						expr_cnt += 2;
					}

					if( val_cnt<NUMS )
							expr_val[val_cnt++] = atof(calcstr);
				}

				if( oper_cnt > 0)
				{
					if( (expr_cnt+2)<EXPR )
					{
						*(expression+expr_cnt) = oper[oper_cnt-1];
						expr_cnt++;
					}

					oper[--oper_cnt] = 0x00;
				}

				arg1 = false;
			}
			else
			{
				printf("No Operation set\n");
				return;
			}
			
			/* if a var value was used just increment the string by one */
			if( bvar )
			{
				bvar = false;
				calcstr = calcstr+1;
			}
			/* else do it till a space is found and the string is still valid */
			else if( !(calcstr=strchr(calcstr,0x20)) && !bvar )
				break;
		}
		
		/* if at the end just one operand is left, close it */
		if( arg1 == true )
		{
			if( (expr_cnt+1)<EXPR )
			{
				*(expression+expr_cnt) = ')';
				expr_cnt++;
			}
		}
	}

	/* calculate the expression created */
	if( false == calc_expr( var, expression, expr_val ) )
	{
		printf("Invalid Expression.\n");
	}

	return;
}

void calc_func( int var, char* str )
{
	char *num = strtok(str, "( )");
	double arg = 0.0f;

	/* get the number by removing space or braces */
	num = strtok(NULL,"( )");

	if( NULL == num )
	{
		printf( "Missing Number.\n" );
		return;
	}

	arg = atof(num);
	
	/* check which function was called */
	if( strstr(str,"log") )
	{
		VAL(0) = log(arg);
		printf( "log(%.2f) = %.2f\n", arg, VAL(0) );
	}
	else if( strstr(str,"exp") )
	{
		VAL(0) = exp(arg);
		printf( "exp(%.2f) = %.2f\n", arg, VAL(0) );
	}
	else if( strstr(str,"cos") )
	{
		VAL(0) = cos(arg);
		printf( "cos(%.2f) = %.2f\n", arg, VAL(0) );
	}
	else if( strstr(str,"sin") )
	{
		VAL(0) = sin(arg);
		printf( "sin(%.2f) = %.2f\n", arg, VAL(0) );
	}
	else if( strstr(str,"sqrt") )
	{
		VAL(0) = sqrt(arg);
		printf( "sqrt(%.2f) = %.2f\n", arg, VAL(0) );
	}
	else if( strstr(str,"tan") )
	{
		VAL(0) = tan(arg);
		printf( "tan(%.2f) = %.2f\n", arg, VAL(0) );
	}

	/* set the var. standard: _ */
	VAL(var) = VAL(0);

	return;
}

bool calc_expr( int var, char* expr, double* val )
{
	ui 	expr_it = 0,
		val_it	= 0,
		oper_cnt= 0;
	double	oper[2]	= {0.0f};
	char	operator= 0x00,
		brack_op= 0x00;
	bool	bracket = false;

	/* go through each byte */
	for(; (expr_it<EXPR)&&(expr[expr_it]!=0x00); expr_it++ )
	{
		switch(expr[expr_it])
		{
			/* bracket: open */
			case '(':
			{
				if( bracket || expr[expr_it-1] == ')' )
				{
					return false;
				}

				bracket = true;
			} break;

			/* bracket: close ( calculating the subtotal */
			case ')':
			{
				/* check if the bracket is open and has at least one operand with operator */
				if( (!bracket || oper_cnt < 1 ) && ( !operator || !brack_op ) )
				{
					return false;
				}

				bracket = false;
				
				/* calculate the 2 operands and calculate it with the last result */
				if( oper_cnt == 2 )
				{					
					if( brack_op )
					{
						VAL(0) = calc( brack_op, VAL(0), calc( operator, oper[0], oper[1] ) );
						brack_op = 0;
					}
					else
					{
						VAL(0) = calc( operator, oper[0], oper[1] );
					}
				}
				/* calculate the number with the last */
				else
				{
					VAL(0) = calc( brack_op, oper[0], VAL(0) );
					brack_op = 0;
				}				

				oper_cnt= 0;
				oper[0] = 0.0f; oper[1] = 0.0f;
				operator= 0;
			} break;

			/* number */
			case 'i':
			{
				/* check if this is the third number in series ( error ) 
				or if no val is left ( error ) */
				if( oper_cnt==2 || val[val_it] <= 0.0f )
				{
					return false;
				}

				oper[oper_cnt++] = val[val_it++];
			} break;

			/* operator */
			default:
			{
				if( val[val_it] <= 0.0f )
				{
					return false;
				}
				
				/* check if the operator is within a bracket or out of a bracket */
				if( bracket )
					operator = expr[expr_it];
				else
					brack_op = expr[expr_it];
			} break;
		}
	}

	/* and assign the result to a var or dont do if not set */
	if( var )
	{
		VAL(var) = VAL(0);
		printf( "%c = %s = %.3f\n", (char)KEY(var), expr, VAL(0) );
	}
	else
	{
		printf( "%s = %.3f\n", expr, VAL(0) );
	}

	return true;
}

double calc( char op, double a, double b )
{
	switch( op )
	{
		case '+': 	return (a+b);
		case '-': 	return (a-b);
		case '/': 	return (a/b);
		case '*': 	return (a*b);
		case '^': 	return pow( a, b );
		default: 	return 0.0f;
	}
}

Code:
[angel - crap.iNC]
> gcc quiz2.c -lm -o quiz2
[angel - crap.iNC]
> ./quiz2
> a:=5
a = 5.000000
> b:=a
b = 5.000000
> :clear
Vars removed
> :vars
No Vars found
> sqrt(5)
sqrt(5.00) = 2
> a:=sqrt(10)
sqrt(10.00) = 3
> a 
a = 3.162278
> c:=*ab   
Var not set!
> c:=* a b
Var not set!
> b:=19
b = 19.000000
> c:=* a b
c = (i*i) = 60.083
> _
_ = 60.083276
> :quit
Byebye.
[angel - crap.iNC]
>
 

Neue Beiträge

Zurück