diff --git a/CHANGELOG.md b/CHANGELOG.md index f56a75d..43b07d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,4 +16,11 @@ ## Changed - Optimized command handling functions -- Updated README.md \ No newline at end of file +- Updated README.md + +# [v2.1.0] 2024-04-15 + +## Added + +- functions for the operations with the stack +- error handling diff --git a/README.md b/README.md index c7bd311..0a308e4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The calculator supports the following operations: | fabs | absolute value of a number | | fatn | arctangent in radians | | fcos | cosine in radians | -| fmul10 | multiply by 10 | +| fmul10 | multiply by 10 | | fdiv10 | divide by 10 | | fexp | exponential function | | fint | get the integer part of a number | @@ -26,6 +26,9 @@ The calculator supports the following operations: | fsqr | square root | | ftan | tangent in radians | | fsgn | gives autonomous of the algebraic sign the number (-1; 0; 1) | +| ss | print the content of the stack | +| sc | clear the stack | +| spop | pop the first value of the stack | Additionally, it accommodates floating-point numbers up to nine digits in both decimal (e.g., 3.14) and scientific (e.g., 8.9e-5) notations. @@ -52,7 +55,6 @@ make multicalc The calculator binary, named multicalc.prg, is located in the /bin directory. - ## Operating Manual The calculator can optionally be run using the [VICE](https://vice-emu.sourceforge.io/) emulator. diff --git a/src/modules/adt_stack.c b/src/modules/adt_stack.c index b918762..ced1c6f 100644 --- a/src/modules/adt_stack.c +++ b/src/modules/adt_stack.c @@ -2,6 +2,9 @@ #include "adt_stack.h" #include "math_helper.h" +#include "system_helper.h" + +extern FP resultFp; void Stack_push( StackNodePtr * topPtr, FP value ) { @@ -18,11 +21,11 @@ void Stack_push( StackNodePtr * topPtr, FP value ) else { FP_printRaw( value ); - puts( "not inserted. No memory available.\n" ); + puts( "[STACK]: not inserted. No memory available." ); } } -void Stack_print( StackNodePtr currentPtr ) +void Stack_printDebug( StackNodePtr currentPtr ) { if ( currentPtr == NULL ) { @@ -43,20 +46,44 @@ void Stack_print( StackNodePtr currentPtr ) } } -void Stack_pop( StackNodePtr * topPtr, FP * popValue ) +void Stack_print( StackNodePtr currentPtr ) +{ + if ( currentPtr == NULL ) + { + puts( "[STACK]: Empty" ); + } + else + { + puts( "--> stack's top <--" ); + while ( currentPtr != NULL ) + { + memcpy( resultFp, currentPtr->data, sizeof( FP ) ); + enableBasicRom(); + FP_printResult(); + disableBasicRom(); + puts( "" ); + currentPtr = currentPtr->nextPtr; + } + puts( "--> stack's bottom <--" ); + } +} + +int Stack_pop( StackNodePtr * topPtr, FP * popValue ) { StackNodePtr tempPtr; if ( Stack_isEmpty( *topPtr ) ) { - puts( "Stack is empty. Cannot pop value." ); - return; + puts( "[STACK]: Empty" ); + return EXIT_FAILURE; } tempPtr = *topPtr; memcpy( *popValue, ( *topPtr )->data, sizeof( FP ) ); *topPtr = ( *topPtr )->nextPtr; free( tempPtr ); + + return EXIT_SUCCESS; } bool Stack_isEmpty( StackNodePtr topPtr ) @@ -68,7 +95,7 @@ void Stack_getTop( StackNodePtr topPtr, FP * topValue) { if ( Stack_isEmpty( topPtr ) ) { - puts( "Stack is empty. Cannot pop value." ); + puts( "[STACK]: Empty" ); return; } @@ -77,13 +104,13 @@ void Stack_getTop( StackNodePtr topPtr, FP * topValue) void Stack_free( StackNodePtr * topPtr ) { - StackNodePtr tempPtr = *topPtr; - StackNodePtr nextPtr; - while ( tempPtr != NULL ) + StackNodePtr tempPtr; + + while ( *topPtr != NULL) { - nextPtr = ( *tempPtr ).nextPtr; + tempPtr = *topPtr; + *topPtr = ( *topPtr )->nextPtr; free( tempPtr ); - tempPtr = nextPtr; - } + } } diff --git a/src/modules/adt_stack.h b/src/modules/adt_stack.h index 7cee467..e4b22ab 100644 --- a/src/modules/adt_stack.h +++ b/src/modules/adt_stack.h @@ -17,8 +17,9 @@ typedef struct stackNode StackNode; typedef StackNode *StackNodePtr; void Stack_push( StackNodePtr * topPtr, FP value ); +void Stack_printDebug( StackNodePtr currentPtr ); void Stack_print( StackNodePtr currentPtr ); -void Stack_pop( StackNodePtr * topPtr, FP * popValue ); +int Stack_pop( StackNodePtr * topPtr, FP * popValue ); bool Stack_isEmpty( StackNodePtr topPtr ); void Stack_getTop( StackNodePtr topPtr, FP * topValue ); void Stack_free( StackNodePtr * topPtr ); diff --git a/src/modules/math_helper.c b/src/modules/math_helper.c index 522dd83..9e53980 100644 --- a/src/modules/math_helper.c +++ b/src/modules/math_helper.c @@ -99,6 +99,12 @@ void FP_mult( void ) void FP_div( void ) { + if ( arg1Fp[ 0 ] == 0 && arg1Fp[ 1 ] == 0 && arg1Fp[ 2 ] == 0 && arg1Fp[ 3 ] == 0 && arg1Fp[ 4 ] == 0 ) + { + puts( "[FP]: Division by zero" ); + return; + } + FP_arg1ToFac(); __asm__ ( "lda #<%v", arg2Fp ); __asm__ ( "ldy #>%v", arg2Fp ); diff --git a/src/modules/math_helper.h b/src/modules/math_helper.h index c49fbf8..e09e2eb 100644 --- a/src/modules/math_helper.h +++ b/src/modules/math_helper.h @@ -3,7 +3,7 @@ #include -#define MAX_ARGUMENT_LENGTH 12 +#define MAX_ARGUMENT_LENGTH 20 typedef uint8_t FP[5]; diff --git a/src/modules/misc_helper.c b/src/modules/misc_helper.c index 38c6061..64e220f 100644 --- a/src/modules/misc_helper.c +++ b/src/modules/misc_helper.c @@ -1,3 +1,5 @@ +#include + #include "misc_helper.h" #include "system_helper.h" #include "adt_stack.h" @@ -10,6 +12,8 @@ extern FP arg1Fp; extern FP arg2Fp; extern FP resultFp; +bool isShowingResult = false; + Operation operations[] = { { "fabs", FP_abs }, @@ -28,6 +32,15 @@ Operation operations[] = { NULL, NULL } // End marker }; +Operation stackOperations[] = +{ + { "ss", printStack }, + { "sc", clearStack }, + { "spop", popfromStack }, + { NULL, NULL } // End marker +}; + + Operator operators[] = { { '+', FP_add }, @@ -55,45 +68,51 @@ void handleArgumentString( char * argumentString ) while ( token != NULL ) { - if ( isdigit( ( unsigned char )token[ 0 ] ) ) - { - handleNumber( token ); - } - else - { - if ( ( unsigned char )token[ 0 ] == '-' && isdigit( ( unsigned char )token[ 1 ] ) ) - { - handleNumber( token ); - } - else - { - handleOperator( token ); - } - } + if ( handleToken( token ) == EXIT_FAILURE ) break; token = strtok( NULL, " " ); } + showResult(); printf( "" ); +} - if ( Stack_isEmpty( stackPtr ) ) +int handleToken( char * token ) +{ + if ( isdigit( ( unsigned char )token[ 0 ]) || + ( ( unsigned char )token[ 0 ] == '-' && + isdigit( ( unsigned char )token[ 1 ] ) ) ) { - puts( "Stack is empty" ); - } - else + if ( handleNumber( token ) == EXIT_FAILURE ) + { + isShowingResult = false; + return EXIT_FAILURE; + } + } + else { - showResult(); + if ( handleOperator( token ) == EXIT_FAILURE ) + { + isShowingResult = false; + return EXIT_FAILURE; + } } - Stack_free( &stackPtr ); + return EXIT_SUCCESS; } -void handleNumber( char * token ) +int handleNumber( char * token ) { if ( strlen( token ) >= sizeof( arg1 ) ) { puts( "Number is too long" ); - return; + return EXIT_FAILURE; + } + + if ( !isValidNumber( token ) ) + { + puts( "Invalid number format" ); + return EXIT_FAILURE; } strncpy( arg1, token, sizeof( arg1 ) - 1 ); @@ -106,40 +125,79 @@ void handleNumber( char * token ) disableBasicRom(); Stack_push( &stackPtr, arg1Fp ); + + return EXIT_SUCCESS; } -void handleOperator( char * token ) +int handleOperator( char * token ) { char operator = token[ 0 ]; - Operator * op = operators; if ( Stack_isEmpty( stackPtr ) ) { - puts( "Stack is empty" ); + puts( "[handleOperator]: Stack is empty." ); + return EXIT_FAILURE; } else { - if ( operator == 'f' ) + switch ( operator ) { - handleFunction( token ); - Stack_push( &stackPtr, resultFp ); - return; + case 'f': + if ( handleFunction( token ) == EXIT_FAILURE ) + { + return EXIT_FAILURE; + } + + isShowingResult = true; + break; + + case 's': + if ( handleStackFunction( token ) == EXIT_FAILURE ) + { + return EXIT_FAILURE; + } + + isShowingResult = false; + break; + + default: + if ( handleFpOperator( token ) == EXIT_FAILURE ) + { + return EXIT_FAILURE; + } + + isShowingResult = true; + break; } - for ( op; op->name != NULL; op++ ) + } + + return EXIT_SUCCESS; +} + +int handleFpOperator( char * token ) +{ + Operator * op = operators; + char operators = token[ 0 ]; + + for ( op; op->name != NULL; op++ ) + { + if ( ( op->name == operators ) ) { - if ( ( op->name == operator ) ) + if ( handleTwoOperandOperation( op->func ) == EXIT_FAILURE ) { - handleTwoOperandOperation( op->func ); - Stack_push( &stackPtr, resultFp ); - return; + break; } + Stack_push( &stackPtr, resultFp ); + return EXIT_SUCCESS; } + } - puts( "Invalid operator" ); - } + puts( "FP operator failure" ); + + return EXIT_FAILURE; } -void handleFunction( char * token ) +int handleFunction( char * token ) { Operation * op = operations; @@ -148,21 +206,52 @@ void handleFunction( char * token ) if ( strcmp( token, op->name ) == 0 ) { handleOneOperandOperation( op->func ); - return; + Stack_push( &stackPtr, resultFp ); + return EXIT_SUCCESS; } } + puts( "Invalid function" ); + + return EXIT_FAILURE; } -void handleTwoOperandOperation( void ( *operation )( void ) ) +int handleStackFunction( char * token ) { - Stack_pop(&stackPtr, &arg1Fp); - Stack_pop(&stackPtr, &arg2Fp); + Operation * op = stackOperations; + + for ( op; op->name != NULL; op++ ) + { + if ( strcmp( token, op->name ) == 0 ) + { + op->func(); + return EXIT_SUCCESS; + } + } + + puts( "Invalid stack function" ); + + return EXIT_FAILURE; +} + +int handleTwoOperandOperation( void ( *operation )( void ) ) +{ + if ( Stack_pop( &stackPtr, &arg1Fp ) == EXIT_FAILURE ) + { + return EXIT_FAILURE; + } + + if ( Stack_pop( &stackPtr, &arg2Fp ) == EXIT_FAILURE ) + { + return EXIT_FAILURE; + } enableBasicRom(); operation(); FP_facToResult(); disableBasicRom(); + + return EXIT_SUCCESS; } void handleOneOperandOperation( void ( *operation )( void ) ) @@ -177,11 +266,21 @@ void handleOneOperandOperation( void ( *operation )( void ) ) void showResult( void ) { - Stack_pop( &stackPtr, &resultFp ); - enableBasicRom(); - FP_printResult(); - disableBasicRom(); - puts( "" ); + if ( isShowingResult ) + { + if ( Stack_isEmpty( stackPtr ) ) + { + puts( "Stack is empty [Show result]" ); + } + else + { + Stack_getTop( stackPtr, &resultFp ); + enableBasicRom(); + FP_printResult(); + disableBasicRom(); + puts( "" ); + } + } } void getUserInput( char * argumentString ) @@ -204,3 +303,38 @@ void getUserInput( char * argumentString ) argumentString[ --len ] = '\0'; } } + +void printStack( void ) +{ + Stack_print( stackPtr ); +} + +void clearStack( void ) +{ + Stack_free( &stackPtr ); +} + +void popfromStack( void ) +{ + Stack_pop(&stackPtr, &resultFp); + + enableBasicRom(); + FP_printResult(); + disableBasicRom(); + puts( "" ); +} + +int isValidNumber( const char *str ) +{ + int i = 0; + + for ( i = 0; str[ i ]; i++ ) + { + if ( !isdigit( str[ i ] ) && str[ i ] != '-' && + str[ i ] != 'e' && str[ i ] != '.' ) + { + return false; + } + } + return true; +} diff --git a/src/modules/misc_helper.h b/src/modules/misc_helper.h index 51fbec4..195d567 100644 --- a/src/modules/misc_helper.h +++ b/src/modules/misc_helper.h @@ -24,12 +24,19 @@ typedef struct void header( void ); void handleArgumentString( char * argumentString ); -void handleNumber( char * token ); -void handleOperator( char * token ); -void handleTwoOperandOperation( void ( *operation )( void ) ); -void handleOneOperandOperation( void ( *operation )( void ) ); +int handleToken( char * token ); +int handleNumber( char * token ); +int handleOperator( char * token ); +int handleTwoOperandOperation( void ( * operation )( void ) ); +void handleOneOperandOperation( void ( * operation )( void ) ); void showResult( void ); void getUserInput( char * argumentString ); -void handleFunction( char * token ); +int handleFunction( char * token ); +void printStack( void ); +void clearStack( void ); +int handleFpOperator( char * token ); +int handleStackFunction( char * token ); +void popfromStack( void ); +int isValidNumber( const char *str ); #endif \ No newline at end of file