# include "doogle999.h"
char backspaceText [ BUFFER_SIZE + 1 ] ; // Pretty dumb waste of memory because only backspace characters, used with send_string to backspace and remove input
char text [ BUFFER_SIZE + 1 ] ; // Used to store input and then output when ready to print
unsigned char inputLocation = 0 ; // Current index in text input
double calc ( char input [ ] ) // Finds value of input char array, relatively small and fast I think
{
char inputToken [ BUFFER_SIZE + 1 ] ; // Input buffer, used when a single token (generally a number) takes up more
unsigned char inputTokenLocation = 0 , inputLocation = 0 ; // Keep track of indices
struct Token tokens [ BUFFER_SIZE + 1 ] ; // Input, converted to tokens, one extra large to accomodate for possible negative sign then open parenthesis as first character
unsigned char tokenCount = 0 ; // Keep track of index
bool dashAsMinus = false ; // Kind of a hacky solution to determining whether to treat a dash as a minus sign or a negative sign
while ( inputLocation < BUFFER_SIZE )
{
short number = input [ inputLocation ] - ' 0 ' ; // Using a short here because both signed char and unsigned char would overflow, potentially
if ( inputLocation = = 0 & & input [ inputLocation ] = = CHAR_SUB & & input [ inputLocation + 1 ] = = CHAR_BEG )
{
tokens [ tokenCount ] . raw . num = 0 ;
tokens [ tokenCount ] . isNum = true ;
tokenCount + + ;
dashAsMinus = true ;
}
if ( ( number < 10 & & number > = 0 ) | | ( inputTokenLocation ! = 0 & & input [ inputLocation ] = = ' . ' ) | | ( ! dashAsMinus & & inputTokenLocation = = 0 & & input [ inputLocation ] = = ' - ' ) )
{
inputToken [ inputTokenLocation ] = input [ inputLocation ] ;
inputTokenLocation + + ;
inputLocation + + ;
}
else
{
if ( inputTokenLocation ! = 0 )
{
// sscanf(inputToken, "%lf", &tokens[tokenCount].raw.num); // I would like to use sscanf here, but the small version of stdio.h on the chip doesn't allow sscanf or its sister functions to be used to process floats
tokens [ tokenCount ] . raw . num = atof ( inputToken ) ;
tokens [ tokenCount ] . isNum = true ;
for ( unsigned char i = 0 ; i < inputTokenLocation + 1 ; i + + )
{
inputToken [ i ] = ' \0 ' ;
}
inputTokenLocation = 0 ;
tokenCount + + ;
dashAsMinus = true ;
}
tokens [ tokenCount ] . isNum = false ;
tokens [ tokenCount ] . raw . op . c = input [ inputLocation ] ;
tokens [ tokenCount ] . raw . op . priority = 0 ;
tokens [ tokenCount ] . raw . op . ltr = true ;
dashAsMinus = false ;
switch ( input [ inputLocation ] )
{
case CHAR_BEG :
break ;
case CHAR_END :
dashAsMinus = true ;
break ;
case CHAR_ADD :
tokens [ tokenCount ] . raw . op . priority = PRIO_ADD ;
break ;
case CHAR_SUB :
tokens [ tokenCount ] . raw . op . priority = PRIO_SUB ;
break ;
case CHAR_MUL :
tokens [ tokenCount ] . raw . op . priority = PRIO_MUL ;
break ;
case CHAR_DIV :
tokens [ tokenCount ] . raw . op . priority = PRIO_DIV ;
break ;
case CHAR_EXP :
tokens [ tokenCount ] . raw . op . priority = PRIO_EXP ;
tokens [ tokenCount ] . raw . op . ltr = false ;
break ;
case CHAR_SIN :
break ;
case CHAR_COS :
break ;
case CHAR_TAN :
break ;
case CHAR_ASN :
break ;
case CHAR_ACS :
break ;
case CHAR_ATN :
break ;
case CHAR_LGE :
break ;
case CHAR_LOG :
break ;
case CHAR_SQT :
break ;
case ' \0 ' :
tokenCount - - ;
inputLocation = BUFFER_SIZE ;
break ;
default :
tokenCount - - ;
break ;
}
tokenCount + + ;
inputLocation + + ;
}
}
struct Token output [ BUFFER_SIZE + 1 ] ; // Final output tokens before evaluation
struct Token opstack [ BUFFER_SIZE + 1 ] ; // Stack of operators
unsigned char outputLocation = 0 , opstackLocation = 0 ; // Keep track of indices
unsigned char numBrackets = 0 ; // The number of parenthesis
for ( unsigned char i = 0 ; i < tokenCount ; i + + )
{
if ( tokens [ i ] . isNum )
{
output [ outputLocation ] = tokens [ i ] ;
outputLocation + + ;
}
else if ( tokens [ i ] . raw . op . c = = CHAR_BEG )
{
opstack [ opstackLocation ] = tokens [ i ] ;
opstackLocation + + ;
}
else if ( tokens [ i ] . raw . op . c = = CHAR_END )
{
while ( opstack [ opstackLocation - 1 ] . raw . op . c ! = CHAR_BEG )
{
output [ outputLocation ] = opstack [ opstackLocation - 1 ] ;
outputLocation + + ;
opstackLocation - - ;
}
opstackLocation - - ;
numBrackets + = 2 ;
}
else if ( tokens [ i ] . raw . op . priority = = 0 )
{
opstack [ opstackLocation ] = tokens [ i ] ;
opstackLocation + + ;
}
else
{
while ( opstackLocation ! = 0
& & ( opstack [ opstackLocation - 1 ] . raw . op . priority = = 0
| | tokens [ i ] . raw . op . priority < opstack [ opstackLocation - 1 ] . raw . op . priority
| | ( tokens [ i ] . raw . op . priority = = opstack [ opstackLocation - 1 ] . raw . op . priority & & opstack [ opstackLocation - 1 ] . raw . op . ltr ) )
& & opstack [ opstackLocation - 1 ] . raw . op . c ! = CHAR_BEG )
{
output [ outputLocation ] = opstack [ opstackLocation - 1 ] ;
outputLocation + + ;
opstackLocation - - ;
}
opstack [ opstackLocation ] = tokens [ i ] ;
opstackLocation + + ;
}
}
tokenCount - = numBrackets ;
for ( signed char i = opstackLocation - 1 ; i > = 0 ; i - - )
{
output [ outputLocation ] = opstack [ i ] ;
outputLocation + + ;
opstackLocation - - ;
}
double answer [ BUFFER_SIZE ] ;
unsigned char answerLocation = 0 ;
for ( unsigned char i = 0 ; i < tokenCount ; i + + )
{
if ( output [ i ] . isNum )
{
answer [ answerLocation ] = output [ i ] . raw . num ;
answerLocation + + ;
}
else
{
if ( output [ i ] . raw . op . priority = = 0 )
{
if ( answerLocation > = 1 )
{
switch ( output [ i ] . raw . op . c )
{
case CHAR_SIN :
answer [ answerLocation - 1 ] = sin ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_COS :
answer [ answerLocation - 1 ] = cos ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_TAN :
answer [ answerLocation - 1 ] = tan ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_ASN :
answer [ answerLocation - 1 ] = asin ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_ACS :
answer [ answerLocation - 1 ] = acos ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_ATN :
answer [ answerLocation - 1 ] = atan ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_LGE :
answer [ answerLocation - 1 ] = log ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_LOG :
answer [ answerLocation - 1 ] = log10 ( answer [ answerLocation - 1 ] ) ;
break ;
case CHAR_SQT :
answer [ answerLocation - 1 ] = sqrt ( answer [ answerLocation - 1 ] ) ;
break ;
}
}
}
else if ( answerLocation > = 2 )
{
switch ( output [ i ] . raw . op . c )
{
case CHAR_ADD :
answer [ answerLocation - 2 ] + = answer [ answerLocation - 1 ] ;
break ;
case CHAR_SUB :
answer [ answerLocation - 2 ] - = answer [ answerLocation - 1 ] ;
break ;
case CHAR_MUL :
answer [ answerLocation - 2 ] * = answer [ answerLocation - 1 ] ;
break ;
case CHAR_DIV :
answer [ answerLocation - 2 ] / = answer [ answerLocation - 1 ] ;
break ;
case CHAR_EXP :
answer [ answerLocation - 2 ] = pow ( answer [ answerLocation - 2 ] , answer [ answerLocation - 1 ] ) ;
break ;
}
answerLocation - - ;
}
}
}
return answer [ 0 ] ;
}
bool process_record_user ( uint16_t keycode , keyrecord_t * record )
{
bool numpadKeyPressed = false ;
if ( record - > event . pressed )
{
if ( ! ( get_mods ( ) & MODS_SHIFT_MASK ) )
{
switch ( keycode )
{
case KC_KP_0 :
numpadKeyPressed = true ;
break ;
case KC_KP_1 :
numpadKeyPressed = true ;
break ;
case KC_KP_2 :
numpadKeyPressed = true ;
break ;
case KC_KP_3 :
numpadKeyPressed = true ;
break ;
case KC_KP_4 :
numpadKeyPressed = true ;
break ;
case KC_KP_5 :
numpadKeyPressed = true ;
break ;
case KC_KP_6 :
numpadKeyPressed = true ;
break ;
case KC_KP_7 :
numpadKeyPressed = true ;
break ;
case KC_KP_8 :
numpadKeyPressed = true ;
break ;
case KC_KP_9 :
numpadKeyPressed = true ;
break ;
}
}
}
if ( numpadKeyPressed & & ! ( host_keyboard_leds ( ) & ( 1 < < USB_LED_NUM_LOCK ) ) )
{
add_key ( KC_NLCK ) ;
send_keyboard_report ( ) ;
}
if ( biton32 ( layer_state ) = = CALC_LAYER )
{
char characterPressed = ' \0 ' ;
bool forceReturnTrue = false ;
if ( record - > event . pressed )
{
if ( ! ( get_mods ( ) & MODS_SHIFT_MASK ) )
{
switch ( keycode )
{
case KC_0 :
characterPressed = ' 0 ' ;
break ;
case KC_1 :
characterPressed = ' 1 ' ;
break ;
case KC_2 :
characterPressed = ' 2 ' ;
break ;
case KC_3 :
characterPressed = ' 3 ' ;
break ;
case KC_4 :
characterPressed = ' 4 ' ;
break ;
case KC_5 :
characterPressed = ' 5 ' ;
break ;
case KC_6 :
characterPressed = ' 6 ' ;
break ;
case KC_7 :
characterPressed = ' 7 ' ;
break ;
case KC_8 :
characterPressed = ' 8 ' ;
break ;
case KC_9 :
characterPressed = ' 9 ' ;
break ;
case KC_MINUS :
characterPressed = CHAR_SUB ;
break ;
case KC_SLASH :
characterPressed = CHAR_DIV ;
break ;
case KC_S :
characterPressed = CHAR_SIN ;
break ;
case KC_C :
characterPressed = CHAR_COS ;
break ;
case KC_T :
characterPressed = CHAR_TAN ;
break ;
case KC_Q :
characterPressed = CHAR_SQT ;
break ;
case KC_L :
characterPressed = CHAR_LGE ;
break ;
case KC_DOT :
characterPressed = ' . ' ;
break ;
case KC_BSPC :
if ( inputLocation > 0 )
{
inputLocation - - ;
}
forceReturnTrue = true ;
break ;
case KC_RSFT :
forceReturnTrue = true ;
break ;
case KC_LSFT :
forceReturnTrue = true ;
break ;
case CALC :
for ( int i = 0 ; i < inputLocation ; i + + )
{
backspaceText [ i ] = ( char ) 8 ;
}
send_string ( backspaceText ) ;
dtostrf ( calc ( text ) , 6 , 6 , text ) ;
send_string ( text ) ;
for ( unsigned char i = 0 ; i < BUFFER_SIZE ; i + + )
{
text [ i ] = ' \0 ' ;
backspaceText [ i ] = ' \0 ' ;
}
inputLocation = 0 ;
break ;
case ENDCALC :
layer_state = 0 ;
break ;
default :
break ;
}
}
else
{
switch ( keycode )
{
case KC_9 :
characterPressed = CHAR_BEG ;
break ;
case KC_0 :
characterPressed = CHAR_END ;
break ;
case KC_EQUAL :
characterPressed = CHAR_ADD ;
break ;
case KC_6 :
characterPressed = CHAR_EXP ;
break ;
case KC_8 :
characterPressed = CHAR_MUL ;
break ;
case KC_S :
characterPressed = CHAR_ASN ;
break ;
case KC_C :
characterPressed = CHAR_ACS ;
break ;
case KC_T :
characterPressed = CHAR_ATN ;
break ;
case KC_L :
characterPressed = CHAR_LOG ;
break ;
default :
break ;
}
}
}
if ( inputLocation < BUFFER_SIZE & & characterPressed ! = ' \0 ' )
{
text [ inputLocation ] = characterPressed ;
inputLocation + + ;
}
return ( ! record - > event . pressed | | ( record - > event . pressed & & ( characterPressed ! = ' \0 ' | | forceReturnTrue ) ) ) ;
}
else
{
return true ;
}
}