I have been working on my Csym project, and after over 400 lines of code, I have created the base engine (does not include symbolic manipulation). It works pretty well, to my knowledge, and I am hoping to soon implement the symbolic functions. Here is the code:

Code:
#include <tice.h>
#include <graphx.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#define MAX_INPUT_LENGTH 50
#define MAX_HISTORY 10

long long intPow(long long base, long long exp) {
    long long result = 1;
    for (long long i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

// Simple expression evaluator
typedef struct {
    const char* expr;
    int pos;
} Parser;

double parseExpression(Parser* p);
double parseTerm(Parser* p);
double parseFactor(Parser* p);
double parsePower(Parser* p);

void skipWhitespace(Parser* p) {
    while (p->expr[p->pos] == ' ') p->pos++;
}

double parseNumber(Parser* p) {
    skipWhitespace(p);
    double result = 0;
    bool hasDecimal = false;
    double decimal = 0.1;

    while (isdigit(p->expr[p->pos]) || p->expr[p->pos] == '.') {
        if (p->expr[p->pos] == '.') {
            hasDecimal = true;
            p->pos++;
            continue;
        }
        if (!hasDecimal) {
            result = result * 10 + (p->expr[p->pos] - '0');
        } else {
            result += (p->expr[p->pos] - '0') * decimal;
            decimal *= 0.1;
        }
        p->pos++;
    }
    return result;
}

double parsePower(Parser* p) {
    double result = parseFactor(p);
    skipWhitespace(p);

    if (p->expr[p->pos] == '^') {
        p->pos++;
        double exponent = parsePower(p);

        // Check if both base and exponent are integers
        double roundedBase = round(result);
        double roundedExp  = round(exponent);

        if (fabs(result - roundedBase) < 1e-9 &&
                fabs(exponent - roundedExp) < 1e-9 &&
                roundedExp >= 0) {
            // Exact integer power
            result = (double)intPow((long long)roundedBase, (long long)roundedExp);
        } else {
            // Fall back to floating point pow()
            result = pow(result, exponent);
        }
    }

    return result;
}


double parseFactor(Parser* p) {
    skipWhitespace(p);

    // Handle negative numbers
    if (p->expr[p->pos] == '-') {
        p->pos++;
        return -parseFactor(p);
    }

    // Handle parentheses
    if (p->expr[p->pos] == '(') {
        p->pos++;
        double result = parseExpression(p);
        skipWhitespace(p);
        if (p->expr[p->pos] == ')') {
            p->pos++;
        }
        return result;
    }
    // Handle functions: sin, cos, tan, log, ln
    if (strncmp(&p->expr[p->pos], "sin", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return sin(arg);
    }
    if (strncmp(&p->expr[p->pos], "cos", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return cos(arg);
    }
    if (strncmp(&p->expr[p->pos], "tan", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return tan(arg);
    }
    if (strncmp(&p->expr[p->pos], "log", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return log10(arg);
    }
    if (strncmp(&p->expr[p->pos], "ln", 2) == 0) {
        p->pos += 2;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return log(arg);
    }
    if (strncmp(&p->expr[p->pos], "pi", 2) == 0) {
        p->pos += 2;
        return M_PI;
    }
    if (strncmp(&p->expr[p->pos], "e", 1) == 0) {
        p->pos += 1;
        return M_E;
    }
// Parse number
    return parseNumber(p);
}

double parseTerm(Parser* p) {
    double result = parsePower(p);

    while (1) {
        skipWhitespace(p);
        char op = p->expr[p->pos];

        if (op == '*') {
            p->pos++;
            result *= parsePower(p);
        } else if (op == '/') {
            p->pos++;
            double divisor = parsePower(p);
            if (divisor != 0) {
                result /= divisor;
            } else {
                return NAN;  // Division by zero
            }
        } else {
            break;
        }
    }

    return result;
}

double parseExpression(Parser* p) {
    double result = parseTerm(p);

    while (1) {
        skipWhitespace(p);
        char op = p->expr[p->pos];

        if (op == '+') {
            p->pos++;
            result += parseTerm(p);
        } else if (op == '-') {
            p->pos++;
            result -= parseTerm(p);
        } else {
            break;
        }
    }

    return result;
}

double evaluate(const char* expr) {
    Parser p = {expr, 0};
    return parseExpression(&p);
}

int main(void) {
    gfx_Begin();
    gfx_SetDrawBuffer();
    gfx_FillScreen(255);
    gfx_SetTextBGColor(255);
    gfx_SetTextScale(2,2);

    const char* text = "Csym Pre-Alpha";
    const char* promptText = "PRESS ENTER";
    int textWidth = gfx_GetStringWidth(text);
    int y = 0;
    int ySpeed = 1;
    int x = (LCD_WIDTH - textWidth) / 2;
    int promptX = (120);
    int promptY = LCD_HEIGHT - 30;
    int flickerCounter = 0;
    bool showPrompt = true;

    while (1) {
        gfx_FillScreen(255);
        gfx_SetTextFGColor(6);
        gfx_SetTextScale(2, 2);
        gfx_PrintStringXY(text, x, y);
        if (showPrompt) {
            gfx_SetTextFGColor(0);
            gfx_SetTextScale(1,1);
            gfx_PrintStringXY(promptText, promptX, promptY);
        }
        gfx_SwapDraw();
        y += ySpeed;
        if (y >= 60) {
            y = 60;
            ySpeed = -1;
        } else if (y <= 0) {
            y = 0;
            ySpeed = 1;
        }
        flickerCounter++;
        if (flickerCounter >= 30) {
            showPrompt = !showPrompt;
            flickerCounter = 0;
        }
        if (os_GetCSC() == sk_Enter) {
            break;
        }

        delay(10);
    }

    char inputBuffer[MAX_INPUT_LENGTH + 1] = {0};
    char historyExpr[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};
    char historyResult[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};
    int historyCount = 0;
    int cursorPos = 0;
    sk_key_t key;
    bool running = true;
    bool alphaMode = false;
    bool secondMode = false;


    while (running) {
        // Clear screen
        gfx_FillScreen(255);

        // Draw prompt
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY("Csym Pre-Alpha", 10, 10);

        // Draw Alpha text
        if (alphaMode) {
            gfx_SetTextFGColor(6);
            gfx_PrintStringXY("A", 200, 10);
        }
        // Draw 2nd Text
        if (secondMode) {
            gfx_SetTextFGColor(8);
            gfx_PrintStringXY("2nd",210,10);
        }
        // Draw input text
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY(inputBuffer, 10, 40);

        // Draw cursor (blinking underscore)
        if ((timer_1_Counter / 20000) % 2) {
            gfx_PrintStringXY("_", 10 + gfx_GetStringWidth(inputBuffer), 40);
        }

        // Draw history - expressions on left, results on right
        gfx_SetTextScale(1, 1);
        gfx_SetTextFGColor(0);
        int historyY = 60;
        for (int i = 0; i < historyCount && i < MAX_HISTORY; i++) {
            // Draw expression on left
            gfx_PrintStringXY(historyExpr[i], 10, historyY);

            // Draw result on right
            gfx_PrintStringXY(historyResult[i], LCD_WIDTH - gfx_GetStringWidth(historyResult[i]) - 10, historyY);

            historyY += 15;
        }

        gfx_SwapDraw();
        key = os_GetCSC();
        if (key) {
            if (boot_CheckOnPressed()) {
                break;
            }
            if (key == sk_Enter) {
                // Save to history if not empty
                if (inputBuffer[0] != '\0' && historyCount < MAX_HISTORY) {
                    // Save expression
                    strcpy(historyExpr[historyCount], inputBuffer);

                    // Evaluate and save result
                    double result = evaluate(inputBuffer);
                    if (isnan(result)) {
                        strcpy(historyResult[historyCount], "Error");
                    } else if (isinf(result)) {
                        strcpy(historyResult[historyCount], "Infinity");
                    } else {
                        // Format result (remove trailing zeros)
                        sprintf(historyResult[historyCount], "%.12f", result);

                        // Remove trailing zeros
                        int len = strlen(historyResult[historyCount]);
                        while (len > 0 && historyResult[historyCount][len-1] == '0') {
                            historyResult[historyCount][len-1] = '\0';
                            len--;
                        }
                        // Remove trailing decimal point
                        if (len > 0 && historyResult[historyCount][len-1] == '.') {
                            historyResult[historyCount][len-1] = '\0';
                        }
                    }

                    historyCount++;
                }
                // Clear input buffer
                inputBuffer[0] = '\0';
                cursorPos = 0;
            } else if (key == sk_Alpha) {
                alphaMode = !alphaMode;
            } else if (key == sk_2nd) {
                secondMode = !secondMode;
            } else if (key == sk_Clear) {
                inputBuffer[0] = '\0';
                cursorPos = 0;
            } else if (key == sk_Del && cursorPos > 0) {
                cursorPos--;
                inputBuffer[cursorPos] = '\0';
            } else if (cursorPos < MAX_INPUT_LENGTH) {
                // Map keys to characters
                char ch = '\0';

                // 2nd Definitions
                if (secondMode) {
                    if (key == sk_Square) {
                        if (cursorPos + 6 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos++] = '1';
                            inputBuffer[cursorPos++] = '/';
                            inputBuffer[cursorPos++] = '2';
                            inputBuffer[cursorPos++] = ')';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                    else if (key == sk_Power) {
                        if (cursorPos + 2 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'p';
                            inputBuffer[cursorPos++] = 'i';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                    else if (key == sk_Div) {
                        if (cursorPos + 1 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'e';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                }
                // ALPHA Definitions
                else if (alphaMode) {
                    // Alpha mode - letters
                    if (key == sk_Math) ch = 'A';
                    else if (key == sk_Apps) ch = 'B';
                    else if (key == sk_Prgm) ch = 'C';
                    else if (key == sk_Recip) ch = 'D';
                    else if (key == sk_Sin) ch = 'E';
                    else if (key == sk_Cos) ch = 'F';
                    else if (key == sk_Tan) ch = 'G';
                    else if (key == sk_Power) ch = 'H';
                    else if (key == sk_Square) ch = 'I';
                    else if (key == sk_Comma) ch = 'J';
                    else if (key == sk_LParen) ch = 'K';
                    else if (key == sk_RParen) ch = 'L';
                    else if (key == sk_Div) ch = 'M';
                    else if (key == sk_Log) ch = 'N';
                    else if (key == sk_7) ch = 'O';
                    else if (key == sk_8) ch = 'P';
                    else if (key == sk_9) ch = 'Q';
                    else if (key == sk_Mul) ch = 'R';
                    else if (key == sk_Ln) ch = 'S';
                    else if (key == sk_4) ch = 'T';
                    else if (key == sk_5) ch = 'U';
                    else if (key == sk_6) ch = 'V';
                    else if (key == sk_Sub) ch = 'W';
                    else if (key == sk_Store) ch = 'X';
                    else if (key == sk_1) ch = 'Y';
                    else if (key == sk_2) ch = 'Z';
                    else if (key == sk_0) ch = ' ';
                    else if (key == sk_DecPnt) ch = ':';
                    else if (key == sk_Add) ch = '"';

                    // Add character to buffer if one was set
                    if (ch != '\0') {
                        inputBuffer[cursorPos] = ch;
                        cursorPos++;
                        inputBuffer[cursorPos] = '\0';

                        // Auto-disable alpha after letter entry (but not for space)
                        if (ch != ' ') {
                            alphaMode = false;
                        }
                    }
                }
                else {
                    // Normal mode - Numbers and operators
                    if (key == sk_0) ch = '0';
                    else if (key == sk_1) ch = '1';
                    else if (key == sk_2) ch = '2';
                    else if (key == sk_3) ch = '3';
                    else if (key == sk_4) ch = '4';
                    else if (key == sk_5) ch = '5';
                    else if (key == sk_6) ch = '6';
                    else if (key == sk_7) ch = '7';
                    else if (key == sk_8) ch = '8';
                    else if (key == sk_9) ch = '9';
                    // Common symbols
                    else if (key == sk_Add) ch = '+';
                    else if (key == sk_Sub) ch = '-';
                    else if (key == sk_Mul) ch = '*';
                    else if (key == sk_Div) ch = '/';
                    else if (key == sk_LParen) ch = '(';
                    else if (key == sk_RParen) ch = ')';
                    else if (key == sk_Power) ch = '^';
                    else if (key == sk_DecPnt) ch = '.';
                    else if (key == sk_Chs) ch = '-';
                    else if (key == sk_Comma) ch = ',';
                    else if (key == sk_GraphVar) ch = 'X';
                    else if (key == sk_Store) ch = '=';
                    else if (key == sk_Square) {
                        if (cursorPos + 2 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '2';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Recip) {
                        if (cursorPos + 3 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '-';
                            inputBuffer[cursorPos++] = '1';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Sin) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 's';
                            inputBuffer[cursorPos++] = 'i';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Cos) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'c';
                            inputBuffer[cursorPos++] = 'o';
                            inputBuffer[cursorPos++] = 's';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Tan) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 't';
                            inputBuffer[cursorPos++] = 'a';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Log) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'l';
                            inputBuffer[cursorPos++] = 'o';
                            inputBuffer[cursorPos++] = 'g';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Ln) {
                        if (cursorPos + 3 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'l';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }

                    // Add single character to buffer if one was set
                    if (ch != '\0') {
                        inputBuffer[cursorPos] = ch;
                        cursorPos++;
                        inputBuffer[cursorPos] = '\0';
                    }
                }

                // Wait for key release
                while (os_GetCSC());
            }
            delay(10);
        }
    }
    gfx_End();
    return 0;
}

If anyone has any suggestions on how to improve this, please tell.
Are you adapting an existing symbolic engine, following/porting a general structure that's been used elsewhere, or creating your own completely from scratch? Having spent much time using and improving gCAS2, incidentally the engine used in Graph3DP for the Casio Prizm and Graph3CE for the TI-84 Plus CE, I know how labyrinthine symbolic and even non-symbolic EOS code can quickly get without lots of pre-planning!
I am probably planning on writing my own CAS engine, I have already got a solid numerical engine created out, so I will probably add a layer to the evaluator that does CAS evaluations.
Progress report! I am almost finished writing the base of the engine! Here is some screenshots!



(thanks to Tari for helping me fix the bbcode)
UPDATE: I have 2 things.
1: I updated the code so that the history works properly and did a few bug fixes.
2: I need help. Does anyone know why, when I try doing something like 9^(1/2) it gives a result like 2.9999999954334 or something.
Here is the code:

Code:
#include <tice.h>
#include <graphx.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#define MAX_INPUT_LENGTH 50
#define MAX_HISTORY 25

long long intPow(long long base, long long exp) {
    long long result = 1;
    for (long long i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

// Simple expression evaluator
typedef struct {
    const char* expr;
    int pos;
} Parser;

double parseExpression(Parser* p);
double parseTerm(Parser* p);
double parseFactor(Parser* p);
double parsePower(Parser* p);

void skipWhitespace(Parser* p) {
    while (p->expr[p->pos] == ' ') p->pos++;
}

double parseNumber(Parser* p) {
    skipWhitespace(p);
    double result = 0;
    bool hasDecimal = false;
    double decimal = 0.1;

    while (isdigit(p->expr[p->pos]) || p->expr[p->pos] == '.') {
        if (p->expr[p->pos] == '.') {
            hasDecimal = true;
            p->pos++;
            continue;
        }
        if (!hasDecimal) {
            result = result * 10 + (p->expr[p->pos] - '0');
        } else {
            result += (p->expr[p->pos] - '0') * decimal;
            decimal *= 0.1;
        }
        p->pos++;
    }
    return result;
}

double parsePower(Parser* p) {
    double result = parseFactor(p);
    skipWhitespace(p);

    if (p->expr[p->pos] == '^') {
        p->pos++;
        double exponent = parsePower(p);

        // Check if both base and exponent are integers
        double roundedBase = round(result);
        double roundedExp  = round(exponent);

        if (fabs(result - roundedBase) < 1e-9 &&
                fabs(exponent - roundedExp) < 1e-9 &&
                roundedExp >= 0) {
            // Exact integer power
            result = (double)intPow((long long)roundedBase, (long long)roundedExp);
        } else {
            // Fall back to floating point pow()
            result = pow(result, exponent);
        }
    }

    return result;
}


double parseFactor(Parser* p) {
    skipWhitespace(p);

    // Handle negative numbers
    if (p->expr[p->pos] == '-') {
        p->pos++;
        return -parseFactor(p);
    }

    // Handle parentheses
    if (p->expr[p->pos] == '(') {
        p->pos++;
        double result = parseExpression(p);
        skipWhitespace(p);
        if (p->expr[p->pos] == ')') {
            p->pos++;
        }
        return result;
    }
    // Handle functions: sin, cos, tan, log, ln
    if (strncmp(&p->expr[p->pos], "sin", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return sin(arg);
    }
    if (strncmp(&p->expr[p->pos], "cos", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return cos(arg);
    }
    if (strncmp(&p->expr[p->pos], "tan", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return tan(arg);
    }
    if (strncmp(&p->expr[p->pos], "log", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return log10(arg);
    }
    if (strncmp(&p->expr[p->pos], "ln", 2) == 0) {
        p->pos += 2;
        if (p->expr[p->pos] == '(') p->pos++;
        double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return log(arg);
    }
    if (strncmp(&p->expr[p->pos], "pi", 2) == 0) {
        p->pos += 2;
        return M_PI;
    }
    if (strncmp(&p->expr[p->pos], "e", 1) == 0) {
        p->pos += 1;
        return M_E;
    }
    // Parse number
    return parseNumber(p);
}

double parseTerm(Parser* p) {
    double result = parsePower(p);

    while (1) {
        skipWhitespace(p);
        char op = p->expr[p->pos];

        if (op == '*') {
            p->pos++;
            result *= parsePower(p);
        } else if (op == '/') {
            p->pos++;
            double divisor = parsePower(p);
            if (divisor != 0) {
                result /= divisor;
            } else {
                return NAN;  // Division by zero
            }
        } else {
            break;
        }
    }

    return result;
}

double parseExpression(Parser* p) {
    double result = parseTerm(p);

    while (1) {
        skipWhitespace(p);
        char op = p->expr[p->pos];

        if (op == '+') {
            p->pos++;
            result += parseTerm(p);
        } else if (op == '-') {
            p->pos++;
            result -= parseTerm(p);
        } else {
            break;
        }
    }

    return result;
}

double evaluate(const char* expr) {
    Parser p = {expr, 0};
    return parseExpression(&p);
}

// Declare history arrays as static to avoid stack overflow
static char historyExpr[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};
static char historyResult[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};

int main(void) {
    gfx_Begin();
    gfx_SetDrawBuffer();
    gfx_FillScreen(255);
    gfx_SetTextBGColor(255);
    gfx_SetTextScale(2,2);

    const char* text = "Csym Pre-Alpha";
    const char* promptText = "PRESS ENTER";
    int textWidth = gfx_GetStringWidth(text);
    int y = 0;
    int ySpeed = 1;
    int x = (LCD_WIDTH - textWidth) / 2;
    int promptX = (120);
    int promptY = LCD_HEIGHT - 30;
    int flickerCounter = 0;
    bool showPrompt = true;

    while (1) {
        gfx_FillScreen(255);
        gfx_SetTextFGColor(6);
        gfx_SetTextScale(2, 2);
        gfx_PrintStringXY(text, x, y);
        if (showPrompt) {
            gfx_SetTextFGColor(0);
            gfx_SetTextScale(1,1);
            gfx_PrintStringXY(promptText, promptX, promptY);
        }
        gfx_SwapDraw();
        y += ySpeed;
        if (y >= 60) {
            y = 60;
            ySpeed = -1;
        } else if (y <= 0) {
            y = 0;
            ySpeed = 1;
        }
        flickerCounter++;
        if (flickerCounter >= 30) {
            showPrompt = !showPrompt;
            flickerCounter = 0;
        }
        if (os_GetCSC() == sk_Enter) {
            break;
        }

        delay(10);
    }

    char inputBuffer[MAX_INPUT_LENGTH + 1] = {0};
    int historyCount = 0;
    int cursorPos = 0;
    sk_key_t key;
    bool running = true;
    bool alphaMode = false;
    bool secondMode = false;


    while (running) {
        // Clear screen
        gfx_FillScreen(255);

        // Draw prompt
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY("Csym Pre-Alpha", 10, 10);

        // Draw Alpha text
        if (alphaMode) {
            gfx_SetTextFGColor(6);
            gfx_PrintStringXY("A", 200, 10);
        }
        // Draw 2nd Text
        if (secondMode) {
            gfx_SetTextFGColor(8);
            gfx_PrintStringXY("2nd",210,10);
        }
        // Draw input text
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY(inputBuffer, 10, 40);

        // Draw cursor (blinking underscore)
        if ((timer_1_Counter / 20000) % 2) {
            gfx_PrintStringXY("_", 10 + gfx_GetStringWidth(inputBuffer), 40);
        }

        // Draw history - expressions on left, results on right (newest first)
        gfx_SetTextScale(1, 1);
        gfx_SetTextFGColor(0);
        int historyY = 60;
        for (int i = historyCount - 1; i >= 0 && historyCount - i <= MAX_HISTORY; i--) {
            // Draw expression on left
            gfx_PrintStringXY(historyExpr[i], 10, historyY);

            // Draw result on right
            gfx_PrintStringXY(historyResult[i], LCD_WIDTH - gfx_GetStringWidth(historyResult[i]) - 10, historyY);

            historyY += 15;
        }

        gfx_SwapDraw();
        key = os_GetCSC();
        if (key) {
            if (boot_CheckOnPressed()) {
                break;
            }
            if (key == sk_Enter) {
                // Save to history if not empty
                if (inputBuffer[0] != '\0') {
                    // If history is full, shift everything up (delete oldest)
                    if (historyCount >= MAX_HISTORY) {
                        for (int i = 0; i < MAX_HISTORY - 1; i++) {
                            strcpy(historyExpr[i], historyExpr[i + 1]);
                            strcpy(historyResult[i], historyResult[i + 1]);
                        }
                        historyCount = MAX_HISTORY - 1;
                    }

                    // Save expression
                    strcpy(historyExpr[historyCount], inputBuffer);

                    // Evaluate and save result
                    double result = evaluate(inputBuffer);
                    if (isnan(result)) {
                        strcpy(historyResult[historyCount], "Error");
                    } else if (isinf(result)) {
                        strcpy(historyResult[historyCount], "Infinity");
                    } else {
                        // Format result (remove trailing zeros)
                        sprintf(historyResult[historyCount], "%.12f", result);

                        // Remove trailing zeros
                        int len = strlen(historyResult[historyCount]);
                        while (len > 0 && historyResult[historyCount][len-1] == '0') {
                            historyResult[historyCount][len-1] = '\0';
                            len--;
                        }
                        // Remove trailing decimal point
                        if (len > 0 && historyResult[historyCount][len-1] == '.') {
                            historyResult[historyCount][len-1] = '\0';
                        }
                    }

                    historyCount++;
                }
                // Clear input buffer
                inputBuffer[0] = '\0';
                cursorPos = 0;
            } else if (key == sk_Alpha) {
                alphaMode = !alphaMode;
            } else if (key == sk_2nd) {
                secondMode = !secondMode;
            } else if (key == sk_Clear) {
                inputBuffer[0] = '\0';
                cursorPos = 0;
            } else if (key == sk_Del && cursorPos > 0) {
                cursorPos--;
                inputBuffer[cursorPos] = '\0';
            } else if (cursorPos < MAX_INPUT_LENGTH) {
                // Map keys to characters
                char ch = '\0';

                // 2nd Definitions
                if (secondMode) {
                    if (key == sk_Square) {
                        if (cursorPos + 6 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos++] = '1';
                            inputBuffer[cursorPos++] = '/';
                            inputBuffer[cursorPos++] = '2';
                            inputBuffer[cursorPos++] = ')';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                    else if (key == sk_Power) {
                        if (cursorPos + 2 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'p';
                            inputBuffer[cursorPos++] = 'i';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                    else if (key == sk_Div) {
                        if (cursorPos + 1 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'e';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                }
                // ALPHA Definitions
                else if (alphaMode) {
                    // Alpha mode - letters
                    if (key == sk_Math) ch = 'A';
                    else if (key == sk_Apps) ch = 'B';
                    else if (key == sk_Prgm) ch = 'C';
                    else if (key == sk_Recip) ch = 'D';
                    else if (key == sk_Sin) ch = 'E';
                    else if (key == sk_Cos) ch = 'F';
                    else if (key == sk_Tan) ch = 'G';
                    else if (key == sk_Power) ch = 'H';
                    else if (key == sk_Square) ch = 'I';
                    else if (key == sk_Comma) ch = 'J';
                    else if (key == sk_LParen) ch = 'K';
                    else if (key == sk_RParen) ch = 'L';
                    else if (key == sk_Div) ch = 'M';
                    else if (key == sk_Log) ch = 'N';
                    else if (key == sk_7) ch = 'O';
                    else if (key == sk_8) ch = 'P';
                    else if (key == sk_9) ch = 'Q';
                    else if (key == sk_Mul) ch = 'R';
                    else if (key == sk_Ln) ch = 'S';
                    else if (key == sk_4) ch = 'T';
                    else if (key == sk_5) ch = 'U';
                    else if (key == sk_6) ch = 'V';
                    else if (key == sk_Sub) ch = 'W';
                    else if (key == sk_Store) ch = 'X';
                    else if (key == sk_1) ch = 'Y';
                    else if (key == sk_2) ch = 'Z';
                    else if (key == sk_0) ch = ' ';
                    else if (key == sk_DecPnt) ch = ':';
                    else if (key == sk_Add) ch = '"';

                    // Add character to buffer if one was set
                    if (ch != '\0') {
                        inputBuffer[cursorPos] = ch;
                        cursorPos++;
                        inputBuffer[cursorPos] = '\0';

                        // Auto-disable alpha after letter entry (but not for space)
                        if (ch != ' ') {
                            alphaMode = false;
                        }
                    }
                }
                else {
                    // Normal mode - Numbers and operators
                    if (key == sk_0) ch = '0';
                    else if (key == sk_1) ch = '1';
                    else if (key == sk_2) ch = '2';
                    else if (key == sk_3) ch = '3';
                    else if (key == sk_4) ch = '4';
                    else if (key == sk_5) ch = '5';
                    else if (key == sk_6) ch = '6';
                    else if (key == sk_7) ch = '7';
                    else if (key == sk_8) ch = '8';
                    else if (key == sk_9) ch = '9';
                    // Common symbols
                    else if (key == sk_Add) ch = '+';
                    else if (key == sk_Sub) ch = '-';
                    else if (key == sk_Mul) ch = '*';
                    else if (key == sk_Div) ch = '/';
                    else if (key == sk_LParen) ch = '(';
                    else if (key == sk_RParen) ch = ')';
                    else if (key == sk_Power) ch = '^';
                    else if (key == sk_DecPnt) ch = '.';
                    else if (key == sk_Chs) ch = '-';
                    else if (key == sk_Comma) ch = ',';
                    else if (key == sk_GraphVar) ch = 'X';
                    else if (key == sk_Store) ch = '=';
                    else if (key == sk_Square) {
                        if (cursorPos + 2 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '2';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Recip) {
                        if (cursorPos + 3 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '-';
                            inputBuffer[cursorPos++] = '1';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Sin) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 's';
                            inputBuffer[cursorPos++] = 'i';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Cos) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'c';
                            inputBuffer[cursorPos++] = 'o';
                            inputBuffer[cursorPos++] = 's';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Tan) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 't';
                            inputBuffer[cursorPos++] = 'a';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Log) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'l';
                            inputBuffer[cursorPos++] = 'o';
                            inputBuffer[cursorPos++] = 'g';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Ln) {
                        if (cursorPos + 3 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'l';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }

                    // Add single character to buffer if one was set
                    if (ch != '\0') {
                        inputBuffer[cursorPos] = ch;
                        cursorPos++;
                        inputBuffer[cursorPos] = '\0';
                    }
                }

                // Wait for key release
                while (os_GetCSC());
            }
            delay(10);
        }
    }
    gfx_End();
    return 0;
}
Because floats have rounding errors, they don't have infinite precision.
How could I make it so that it rounds it to six decimal points? (So that 2.9999996524738 rounds into 3
Fixed code so that 9^(1/2) gives 3

I changed all doubles to long doubles, changed pow to powl, changed fabs to fabsl, and f to Lf in printf functions.


Code:
#include <tice.h>
#include <graphx.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#define MAX_INPUT_LENGTH 50
#define MAX_HISTORY 25

long long intPow(long long base, long long exp) {
    long long result = 1;
    for (long long i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

// Simple expression evaluator
typedef struct {
    const char* expr;
    int pos;
} Parser;

long double parseExpression(Parser* p);
long double parseTerm(Parser* p);
long double parseFactor(Parser* p);
long double parsePower(Parser* p);

void skipWhitespace(Parser* p) {
    while (p->expr[p->pos] == ' ') p->pos++;
}

long double parseNumber(Parser* p) {
    skipWhitespace(p);
    long double result = 0;
    bool hasDecimal = false;
    long double decimal = 0.1;

    while (isdigit(p->expr[p->pos]) || p->expr[p->pos] == '.') {
        if (p->expr[p->pos] == '.') {
            hasDecimal = true;
            p->pos++;
            continue;
        }
        if (!hasDecimal) {
            result = result * 10 + (p->expr[p->pos] - '0');
        } else {
            result += (p->expr[p->pos] - '0') * decimal;
            decimal *= 0.1;
        }
        p->pos++;
    }
    return result;
}

long double parsePower(Parser* p) {
    long double result = parseFactor(p);
    skipWhitespace(p);

    if (p->expr[p->pos] == '^') {
        p->pos++;
        long double exponent = parsePower(p);

        // Check if both base and exponent are integers
        long double roundedBase = round(result);
        long double roundedExp  = round(exponent);

        if (fabsl(result - roundedBase) < 1e-9 &&
                fabsl(exponent - roundedExp) < 1e-9 &&
                roundedExp >= 0) {
            // Exact integer power
            result = (long double)intPow((long long)roundedBase, (long long)roundedExp);
        } else {
            // Fall back to floating point pow()
            result = powl(result, exponent);
        }
    }

    return result;
}


long double parseFactor(Parser* p) {
    skipWhitespace(p);

    // Handle negative numbers
    if (p->expr[p->pos] == '-') {
        p->pos++;
        return -parseFactor(p);
    }

    // Handle parentheses
    if (p->expr[p->pos] == '(') {
        p->pos++;
        long double result = parseExpression(p);
        skipWhitespace(p);
        if (p->expr[p->pos] == ')') {
            p->pos++;
        }
        return result;
    }
    // Handle functions: sin, cos, tan, log, ln
    if (strncmp(&p->expr[p->pos], "sin", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        long double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return sin(arg);
    }
    if (strncmp(&p->expr[p->pos], "cos", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        long double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return cos(arg);
    }
    if (strncmp(&p->expr[p->pos], "tan", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        long double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return tan(arg);
    }
    if (strncmp(&p->expr[p->pos], "log", 3) == 0) {
        p->pos += 3;
        if (p->expr[p->pos] == '(') p->pos++;
        long double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return log10(arg);
    }
    if (strncmp(&p->expr[p->pos], "ln", 2) == 0) {
        p->pos += 2;
        if (p->expr[p->pos] == '(') p->pos++;
        long double arg = parseExpression(p);
        if (p->expr[p->pos] == ')') p->pos++;
        return log(arg);
    }
    if (strncmp(&p->expr[p->pos], "pi", 2) == 0) {
        p->pos += 2;
        return M_PI;
    }
    if (strncmp(&p->expr[p->pos], "e", 1) == 0) {
        p->pos += 1;
        return M_E;
    }
    // Parse number
    return parseNumber(p);
}

long double parseTerm(Parser* p) {
    long double result = parsePower(p);

    while (1) {
        skipWhitespace(p);
        char op = p->expr[p->pos];

        if (op == '*') {
            p->pos++;
            result *= parsePower(p);
        } else if (op == '/') {
            p->pos++;
            long double divisor = parsePower(p);
            if (divisor != 0) {
                result /= divisor;
            } else {
                return NAN;  // Division by zero
            }
        } else {
            break;
        }
    }

    return result;
}

long double parseExpression(Parser* p) {
    long double result = parseTerm(p);

    while (1) {
        skipWhitespace(p);
        char op = p->expr[p->pos];

        if (op == '+') {
            p->pos++;
            result += parseTerm(p);
        } else if (op == '-') {
            p->pos++;
            result -= parseTerm(p);
        } else {
            break;
        }
    }

    return result;
}

long double evaluate(const char* expr) {
    Parser p = {expr, 0};
    return parseExpression(&p);
}

// Declare history arrays as static to avoid stack overflow
static char historyExpr[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};
static char historyResult[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};

int main(void) {
    gfx_Begin();
    gfx_SetDrawBuffer();
    gfx_FillScreen(255);
    gfx_SetTextBGColor(255);
    gfx_SetTextScale(2,2);

    const char* text = "Csym Pre-Alpha";
    const char* promptText = "PRESS ENTER";
    int textWidth = gfx_GetStringWidth(text);
    int y = 0;
    int ySpeed = 1;
    int x = (LCD_WIDTH - textWidth) / 2;
    int promptX = (120);
    int promptY = LCD_HEIGHT - 30;
    int flickerCounter = 0;
    bool showPrompt = true;

    while (1) {
        gfx_FillScreen(255);
        gfx_SetTextFGColor(6);
        gfx_SetTextScale(2, 2);
        gfx_PrintStringXY(text, x, y);
        if (showPrompt) {
            gfx_SetTextFGColor(0);
            gfx_SetTextScale(1,1);
            gfx_PrintStringXY(promptText, promptX, promptY);
        }
        gfx_SwapDraw();
        y += ySpeed;
        if (y >= 60) {
            y = 60;
            ySpeed = -1;
        } else if (y <= 0) {
            y = 0;
            ySpeed = 1;
        }
        flickerCounter++;
        if (flickerCounter >= 30) {
            showPrompt = !showPrompt;
            flickerCounter = 0;
        }
        if (os_GetCSC() == sk_Enter) {
            break;
        }

        delay(10);
    }

    char inputBuffer[MAX_INPUT_LENGTH + 1] = {0};
    int historyCount = 0;
    int cursorPos = 0;
    sk_key_t key;
    bool running = true;
    bool alphaMode = false;
    bool secondMode = false;


    while (running) {
        // Clear screen
        gfx_FillScreen(255);

        // Draw prompt
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY("Csym Pre-Alpha", 10, 10);

        // Draw Alpha text
        if (alphaMode) {
            gfx_SetTextFGColor(6);
            gfx_PrintStringXY("A", 200, 10);
        }
        // Draw 2nd Text
        if (secondMode) {
            gfx_SetTextFGColor(8);
            gfx_PrintStringXY("2nd",210,10);
        }
        // Draw input text
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY(inputBuffer, 10, 40);

        // Draw cursor (blinking underscore)
        if ((timer_1_Counter / 20000) % 2) {
            gfx_PrintStringXY("_", 10 + gfx_GetStringWidth(inputBuffer), 40);
        }

        // Draw history - expressions on left, results on right (newest first)
        gfx_SetTextScale(1, 1);
        gfx_SetTextFGColor(0);
        int historyY = 60;
        for (int i = historyCount - 1; i >= 0 && historyCount - i <= MAX_HISTORY; i--) {
            // Draw expression on left
            gfx_PrintStringXY(historyExpr[i], 10, historyY);

            // Draw result on right
            gfx_PrintStringXY(historyResult[i], LCD_WIDTH - gfx_GetStringWidth(historyResult[i]) - 10, historyY);

            historyY += 15;
        }

        gfx_SwapDraw();
        key = os_GetCSC();
        if (key) {
            if (boot_CheckOnPressed()) {
                break;
            }
            if (key == sk_Enter) {
                // Save to history if not empty
                if (inputBuffer[0] != '\0') {
                    // If history is full, shift everything up (delete oldest)
                    if (historyCount >= MAX_HISTORY) {
                        for (int i = 0; i < MAX_HISTORY - 1; i++) {
                            strcpy(historyExpr[i], historyExpr[i + 1]);
                            strcpy(historyResult[i], historyResult[i + 1]);
                        }
                        historyCount = MAX_HISTORY - 1;
                    }

                    // Save expression
                    strcpy(historyExpr[historyCount], inputBuffer);

                    // Evaluate and save result
                    long double result = evaluate(inputBuffer);
                    if (isnan(result)) {
                        strcpy(historyResult[historyCount], "Error");
                    } else if (isinf(result)) {
                        strcpy(historyResult[historyCount], "Infinity");
                    } else {
                        // Format result (remove trailing zeros)
                        sprintf(historyResult[historyCount], "%.12Lf", result);

                        // Remove trailing zeros
                        int len = strlen(historyResult[historyCount]);
                        while (len > 0 && historyResult[historyCount][len-1] == '0') {
                            historyResult[historyCount][len-1] = '\0';
                            len--;
                        }
                        // Remove trailing decimal point
                        if (len > 0 && historyResult[historyCount][len-1] == '.') {
                            historyResult[historyCount][len-1] = '\0';
                        }
                    }

                    historyCount++;
                }
                // Clear input buffer
                inputBuffer[0] = '\0';
                cursorPos = 0;
            } else if (key == sk_Alpha) {
                alphaMode = !alphaMode;
            } else if (key == sk_2nd) {
                secondMode = !secondMode;
            } else if (key == sk_Clear) {
                inputBuffer[0] = '\0';
                cursorPos = 0;
            } else if (key == sk_Del && cursorPos > 0) {
                cursorPos--;
                inputBuffer[cursorPos] = '\0';
            } else if (cursorPos < MAX_INPUT_LENGTH) {
                // Map keys to characters
                char ch = '\0';

                // 2nd Definitions
                if (secondMode) {
                    if (key == sk_Square) {
                        if (cursorPos + 6 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos++] = '1';
                            inputBuffer[cursorPos++] = '/';
                            inputBuffer[cursorPos++] = '2';
                            inputBuffer[cursorPos++] = ')';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                    else if (key == sk_Power) {
                        if (cursorPos + 2 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'p';
                            inputBuffer[cursorPos++] = 'i';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                    else if (key == sk_Div) {
                        if (cursorPos + 1 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'e';
                            inputBuffer[cursorPos] = '\0';
                            secondMode = false;
                        }
                    }
                }
                // ALPHA Definitions
                else if (alphaMode) {
                    // Alpha mode - letters
                    if (key == sk_Math) ch = 'A';
                    else if (key == sk_Apps) ch = 'B';
                    else if (key == sk_Prgm) ch = 'C';
                    else if (key == sk_Recip) ch = 'D';
                    else if (key == sk_Sin) ch = 'E';
                    else if (key == sk_Cos) ch = 'F';
                    else if (key == sk_Tan) ch = 'G';
                    else if (key == sk_Power) ch = 'H';
                    else if (key == sk_Square) ch = 'I';
                    else if (key == sk_Comma) ch = 'J';
                    else if (key == sk_LParen) ch = 'K';
                    else if (key == sk_RParen) ch = 'L';
                    else if (key == sk_Div) ch = 'M';
                    else if (key == sk_Log) ch = 'N';
                    else if (key == sk_7) ch = 'O';
                    else if (key == sk_8) ch = 'P';
                    else if (key == sk_9) ch = 'Q';
                    else if (key == sk_Mul) ch = 'R';
                    else if (key == sk_Ln) ch = 'S';
                    else if (key == sk_4) ch = 'T';
                    else if (key == sk_5) ch = 'U';
                    else if (key == sk_6) ch = 'V';
                    else if (key == sk_Sub) ch = 'W';
                    else if (key == sk_Store) ch = 'X';
                    else if (key == sk_1) ch = 'Y';
                    else if (key == sk_2) ch = 'Z';
                    else if (key == sk_0) ch = ' ';
                    else if (key == sk_DecPnt) ch = ':';
                    else if (key == sk_Add) ch = '"';

                    // Add character to buffer if one was set
                    if (ch != '\0') {
                        inputBuffer[cursorPos] = ch;
                        cursorPos++;
                        inputBuffer[cursorPos] = '\0';

                        // Auto-disable alpha after letter entry (but not for space)
                        if (ch != ' ') {
                            alphaMode = false;
                        }
                    }
                }
                else {
                    // Normal mode - Numbers and operators
                    if (key == sk_0) ch = '0';
                    else if (key == sk_1) ch = '1';
                    else if (key == sk_2) ch = '2';
                    else if (key == sk_3) ch = '3';
                    else if (key == sk_4) ch = '4';
                    else if (key == sk_5) ch = '5';
                    else if (key == sk_6) ch = '6';
                    else if (key == sk_7) ch = '7';
                    else if (key == sk_8) ch = '8';
                    else if (key == sk_9) ch = '9';
                    // Common symbols
                    else if (key == sk_Add) ch = '+';
                    else if (key == sk_Sub) ch = '-';
                    else if (key == sk_Mul) ch = '*';
                    else if (key == sk_Div) ch = '/';
                    else if (key == sk_LParen) ch = '(';
                    else if (key == sk_RParen) ch = ')';
                    else if (key == sk_Power) ch = '^';
                    else if (key == sk_DecPnt) ch = '.';
                    else if (key == sk_Chs) ch = '-';
                    else if (key == sk_Comma) ch = ',';
                    else if (key == sk_GraphVar) ch = 'X';
                    else if (key == sk_Store) ch = '=';
                    else if (key == sk_Square) {
                        if (cursorPos + 2 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '2';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Recip) {
                        if (cursorPos + 3 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = '^';
                            inputBuffer[cursorPos++] = '-';
                            inputBuffer[cursorPos++] = '1';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Sin) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 's';
                            inputBuffer[cursorPos++] = 'i';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Cos) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'c';
                            inputBuffer[cursorPos++] = 'o';
                            inputBuffer[cursorPos++] = 's';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Tan) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 't';
                            inputBuffer[cursorPos++] = 'a';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Log) {
                        if (cursorPos + 4 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'l';
                            inputBuffer[cursorPos++] = 'o';
                            inputBuffer[cursorPos++] = 'g';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }
                    else if (key == sk_Ln) {
                        if (cursorPos + 3 <= MAX_INPUT_LENGTH) {
                            inputBuffer[cursorPos++] = 'l';
                            inputBuffer[cursorPos++] = 'n';
                            inputBuffer[cursorPos++] = '(';
                            inputBuffer[cursorPos] = '\0';
                        }
                    }

                    // Add single character to buffer if one was set
                    if (ch != '\0') {
                        inputBuffer[cursorPos] = ch;
                        cursorPos++;
                        inputBuffer[cursorPos] = '\0';
                    }
                }

                // Wait for key release
                while (os_GetCSC());
            }
            delay(10);
        }
    }
    gfx_End();
    return 0;
}


I decided to test the classic .1+.2 and to test .64^(1/2) and both were off.

The reason is most decimal numbers can't be represented by a finite amount of binary digits and that causes error.
TI gets around this by using a bcd float format.
This project has been a mess since the beginning, and I have been using AI to write a lot of slow C code. I'm going to hopefully get chatGPT to spit out a working version of this, since I have been doing other stuff (arduino coding). I will hopefully get a working build of this soon, and probably try to rewrite it sometime in the future.

edit:here's what chatGPT made:

Code:
#include <tice.h>
#include <graphx.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_INPUT_LENGTH 50
#define MAX_HISTORY 25
#define MAX_VAR_NAME 8

// ---------- Expression Nodes ----------
typedef enum { NUM, VAR, ADD, SUB, MUL, DIV, POW, FUNC } NodeType;

typedef struct ExprNode {
    NodeType type;
    long double value;          // for numbers
    char var[MAX_VAR_NAME];     // for variables
    char funcName[MAX_VAR_NAME]; // for functions
    struct ExprNode* left;
    struct ExprNode* right;
} ExprNode;

// ---------- Memory Helpers ----------
ExprNode* newNum(long double val) {
    ExprNode* n = malloc(sizeof(ExprNode));
    n->type = NUM; n->value = val; n->left = n->right = NULL; n->var[0]='\0'; n->funcName[0]='\0';
    return n;
}

ExprNode* newVar(const char* name) {
    ExprNode* n = malloc(sizeof(ExprNode));
    n->type = VAR; strcpy(n->var,name); n->left=n->right=NULL; n->funcName[0]='\0';
    return n;
}

ExprNode* newOp(NodeType type, ExprNode* l, ExprNode* r) {
    ExprNode* n = malloc(sizeof(ExprNode));
    n->type = type; n->left=l; n->right=r; n->var[0]='\0'; n->funcName[0]='\0'; n->value=0;
    return n;
}

ExprNode* newFunc(const char* name, ExprNode* arg) {
    ExprNode* n = malloc(sizeof(ExprNode));
    n->type = FUNC; strcpy(n->funcName,name); n->left=arg; n->right=NULL; n->var[0]='\0'; n->value=0;
    return n;
}

// ---------- Parser ----------
typedef struct { const char* expr; int pos; } Parser;

void skipWS(Parser* p) { while (p->expr[p->pos]==' ') p->pos++; }

long double parseNumber(Parser* p) {
    skipWS(p);
    long double val = 0; bool dec=false; long double frac=0.1;
    while (isdigit(p->expr[p->pos]) || p->expr[p->pos]=='.') {
        if (p->expr[p->pos]=='.') { dec=true; p->pos++; continue; }
        if (!dec) val=val*10+(p->expr[p->pos]-'0');
        else { val+=(p->expr[p->pos]-'0')*frac; frac*=0.1; }
        p->pos++;
    }
    return val;
}

bool parseVarName(Parser* p, char* buf) {
    skipWS(p);
    int i=0;
    while (isalnum(p->expr[p->pos]) && i<MAX_VAR_NAME-1) buf[i++] = p->expr[p->pos++];
    buf[i]='\0';
    return i>0;
}

// Forward declarations
ExprNode* parseExpr(Parser* p);
ExprNode* parseTerm(Parser* p);
ExprNode* parseFactor(Parser* p);
ExprNode* parsePower(Parser* p);

ExprNode* parseFactor(Parser* p) {
    skipWS(p);
    // Parentheses
    if (p->expr[p->pos]=='(') { p->pos++; ExprNode* e=parseExpr(p); skipWS(p); if (p->expr[p->pos]==')') p->pos++; return e; }
    // Unary minus
    if (p->expr[p->pos]=='-') { p->pos++; return newOp(SUB,newNum(0),parseFactor(p)); }

    // Function detection
    char buf[MAX_VAR_NAME];
    int start = p->pos;
    if (parseVarName(p, buf)) {
        skipWS(p);
        if (p->expr[p->pos]=='(') { // function
            p->pos++; // skip '('
            ExprNode* arg = parseExpr(p);
            skipWS(p); if (p->expr[p->pos]==')') p->pos++;
            return newFunc(buf,arg);
        } else { // variable
            return newVar(buf);
        }
    }

    return newNum(parseNumber(p));
}

ExprNode* parsePower(Parser* p) {
    ExprNode* base = parseFactor(p);
    skipWS(p);
    if (p->expr[p->pos]=='^') { p->pos++; return newOp(POW, base, parsePower(p)); }
    return base;
}

ExprNode* parseTerm(Parser* p) {
    ExprNode* left=parsePower(p);
    while (1) {
        skipWS(p);
        char op=p->expr[p->pos];
        if (op=='*') { p->pos++; left=newOp(MUL,left,parsePower(p)); }
        else if (op=='/') { p->pos++; left=newOp(DIV,left,parsePower(p)); }
        else break;
    }
    return left;
}

ExprNode* parseExpr(Parser* p) {
    ExprNode* left=parseTerm(p);
    while (1) {
        skipWS(p);
        char op=p->expr[p->pos];
        if (op=='+') { p->pos++; left=newOp(ADD,left,parseTerm(p)); }
        else if (op=='-') { p->pos++; left=newOp(SUB,left,parseTerm(p)); }
        else break;
    }
    return left;
}

ExprNode* parseInput(const char* input) {
    Parser p = { input, 0 };
    return parseExpr(&p);
}

// ---------- Simplification ----------
bool isZero(ExprNode* n) { return n && n->type==NUM && fabs(n->value)<1e-12; }
bool isOne(ExprNode* n) { return n && n->type==NUM && fabs(n->value-1)<1e-12; }
bool isNum(ExprNode* n) { return n && n->type==NUM; }

ExprNode* simplify(ExprNode* n) {
    if (!n) return NULL;
    n->left = simplify(n->left);
    n->right = simplify(n->right);

    if (n->type==ADD || n->type==SUB || n->type==MUL || n->type==DIV || n->type==POW) {
        if (isNum(n->left) && isNum(n->right)) {
            switch(n->type){
                case ADD: n->type=NUM; n->value=n->left->value+n->right->value; free(n->left); free(n->right); n->left=n->right=NULL; break;
                case SUB: n->type=NUM; n->value=n->left->value-n->right->value; free(n->left); free(n->right); n->left=n->right=NULL; break;
                case MUL: n->type=NUM; n->value=n->left->value*n->right->value; free(n->left); free(n->right); n->left=n->right=NULL; break;
                case DIV: n->type=NUM; n->value=n->left->value/n->right->value; free(n->left); free(n->right); n->left=n->right=NULL; break;
                case POW: n->type=NUM; n->value=powl(n->left->value,n->right->value); free(n->left); free(n->right); n->left=n->right=NULL; break;
                default: break;
            }
        }
    }

    // Simplify identities
    if (n->type==ADD) { if (isZero(n->left)) { ExprNode* t=n->right; free(n->left); free(n); return t; }
                        if (isZero(n->right)) { ExprNode* t=n->left; free(n->right); free(n); return t; } }
    if (n->type==SUB) { if (isZero(n->left)) { ExprNode* t=newOp(SUB,newNum(0),n->right); free(n->left); free(n); return t; }
                        if (isZero(n->right)) { ExprNode* t=n->left; free(n->right); free(n); return t; } }
    if (n->type==MUL) { if (isZero(n->left)||isZero(n->right)) { free(n->left); free(n->right); n->type=NUM; n->value=0; n->left=n->right=NULL; }
                        if (isOne(n->left)) { ExprNode* t=n->right; free(n->left); free(n); return t; }
                        if (isOne(n->right)) { ExprNode* t=n->left; free(n->right); free(n); return t; } }
    if (n->type==DIV) { if (isOne(n->right)) { ExprNode* t=n->left; free(n->right); free(n); return t; } }
    if (n->type==POW) { if (isOne(n->right)) { ExprNode* t=n->left; free(n->right); free(n); return t; }
                        if (isZero(n->right)) { free(n->left); free(n->right); n->type=NUM; n->value=1; n->left=n->right=NULL; } }
    if (n->type==FUNC && n->left && isNum(n->left)) {
        long double v = n->left->value;
        if (strcmp(n->funcName,"sin")==0) n->type=NUM, n->value=sinl(v), free(n->left), n->left=NULL;
        else if (strcmp(n->funcName,"cos")==0) n->type=NUM, n->value=cosl(v), free(n->left), n->left=NULL;
        else if (strcmp(n->funcName,"tan")==0) n->type=NUM, n->value=tanl(v), free(n->left), n->left=NULL;
        else if (strcmp(n->funcName,"exp")==0) n->type=NUM, n->value=expl(v), free(n->left), n->left=NULL;
        else if (strcmp(n->funcName,"ln")==0) n->type=NUM, n->value=logl(v), free(n->left), n->left=NULL;
        else if (strcmp(n->funcName,"log")==0) n->type=NUM, n->value=log10l(v), free(n->left), n->left=NULL;
    }

    return n;
}

// ---------- Pretty Print ----------
void printExpr(ExprNode* n, char* buf) {
    if (!n) return;
    char tmp[100]; tmp[0]='\0';
    switch(n->type) {
        case NUM: sprintf(tmp,"%.12Lf",n->value); break;
        case VAR: sprintf(tmp,"%s",n->var); break;
        case ADD: sprintf(tmp,"("); printExpr(n->left,tmp+strlen(tmp)); strcat(tmp,"+"); printExpr(n->right,tmp+strlen(tmp)); strcat(tmp,")"); break;
        case SUB: sprintf(tmp,"("); printExpr(n->left,tmp+strlen(tmp)); strcat(tmp,"-"); printExpr(n->right,tmp+strlen(tmp)); strcat(tmp,")"); break;
        case MUL: sprintf(tmp,"("); printExpr(n->left,tmp+strlen(tmp)); strcat(tmp,"*"); printExpr(n->right,tmp+strlen(tmp)); strcat(tmp,")"); break;
        case DIV: sprintf(tmp,"("); printExpr(n->left,tmp+strlen(tmp)); strcat(tmp,"/"); printExpr(n->right,tmp+strlen(tmp)); strcat(tmp,")"); break;
        case POW: sprintf(tmp,"("); printExpr(n->left,tmp+strlen(tmp)); strcat(tmp,"^"); printExpr(n->right,tmp+strlen(tmp)); strcat(tmp,")"); break;
        case FUNC: sprintf(tmp,"%s(",n->funcName); printExpr(n->left,tmp+strlen(tmp)); strcat(tmp,")"); break;
    }
    strcat(buf,tmp);
}

// ---------- History ----------
static char historyExpr[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};
static char historyResult[MAX_HISTORY][MAX_INPUT_LENGTH + 1] = {0};

// ---------- Calculator UI ----------
int main(void) {
    gfx_Begin();
    gfx_SetDrawBuffer();
    gfx_FillScreen(255);
    gfx_SetTextBGColor(255);
    gfx_SetTextScale(2,2);

    const char* text = "Csym Pre-Alpha";
    const char* promptText = "PRESS ENTER";
    int textWidth = gfx_GetStringWidth(text);
    int y = 0;
    int ySpeed = 1;
    int x = (LCD_WIDTH - textWidth) / 2;
    int promptX = 120;
    int promptY = LCD_HEIGHT - 30;
    int flickerCounter = 0;
    bool showPrompt = true;

    while (1) {
        gfx_FillScreen(255);
        gfx_SetTextFGColor(6);
        gfx_SetTextScale(2, 2);
        gfx_PrintStringXY(text, x, y);
        if (showPrompt) {
            gfx_SetTextFGColor(0);
            gfx_SetTextScale(1,1);
            gfx_PrintStringXY(promptText, promptX, promptY);
        }
        gfx_SwapDraw();
        y += ySpeed;
        if (y >= 60) { y = 60; ySpeed = -1; }
        else if (y <= 0) { y = 0; ySpeed = 1; }
        flickerCounter++;
        if (flickerCounter >= 30) { showPrompt = !showPrompt; flickerCounter = 0; }
        if (os_GetCSC() == sk_Enter) break;
        delay(10);
    }

    char inputBuffer[MAX_INPUT_LENGTH + 1] = {0};
    int historyCount = 0;
    int cursorPos = 0;
    sk_key_t key;
    bool running = true;

    while (running) {
        gfx_FillScreen(255);
        gfx_SetTextFGColor(0);
        gfx_SetTextScale(1, 1);
        gfx_PrintStringXY("Csym Pre-Alpha", 10, 10);

        gfx_SetTextFGColor(0);
        gfx_PrintStringXY(inputBuffer, 10, 40);
        if ((timer_1_Counter / 20000) % 2) gfx_PrintStringXY("_", 10 + gfx_GetStringWidth(inputBuffer), 40);

        int historyY = 60;
        for (int i = historyCount - 1; i >= 0 && historyCount - i <= MAX_HISTORY; i--) {
            gfx_PrintStringXY(historyExpr[i], 10, historyY);
            gfx_PrintStringXY(historyResult[i], LCD_WIDTH - gfx_GetStringWidth(historyResult[i]) - 10, historyY);
            historyY += 15;
        }

        gfx_SwapDraw();
        key = os_GetCSC();
        if (key) {
            if (boot_CheckOnPressed()) break;
            if (key == sk_Enter && inputBuffer[0]!='\0') {
                if (historyCount>=MAX_HISTORY) { for(int i=0;i<MAX_HISTORY-1;i++){strcpy(historyExpr[i],historyExpr[i+1]); strcpy(historyResult[i],historyResult[i+1]);} historyCount=MAX_HISTORY-1; }
                strcpy(historyExpr[historyCount], inputBuffer);

                ExprNode* exprTree = parseInput(inputBuffer);
                exprTree = simplify(exprTree);
                char buf[100];
                buf[0]='\0';
                printExpr(exprTree, buf);
                strcpy(historyResult[historyCount], buf);

                historyCount++;
                inputBuffer[0]='\0';
                cursorPos=0;
            } else if (key == sk_Clear) { inputBuffer[0]='\0'; cursorPos=0; }
            else if (key == sk_Del && cursorPos>0) { cursorPos--; inputBuffer[cursorPos]='\0'; }
            else if (cursorPos < MAX_INPUT_LENGTH) {
                char ch='\0';
                if (key>=sk_0 && key<=sk_9) ch='0'+key-sk_0;
                else if (key==sk_Add) ch='+';
                else if (key==sk_Sub) ch='-';
                else if (key==sk_Mul) ch='*';
                else if (key==sk_Div) ch='/';
                else if (key==sk_LParen) ch='(';
                else if (key==sk_RParen) ch=')';
                else if (key==sk_Power) ch='^';
                if (ch!='\0') { inputBuffer[cursorPos++]=ch; inputBuffer[cursorPos]='\0'; }
                while(os_GetCSC());
            }
            delay(10);
        }
    }

    gfx_End();
    return 0;
}

This hasn't been tested, and probably doesn't work.

KermMartian wrote:
*
0- Having spent much time using and improving gCAS2, incidentally the engine used in Graph3DP for the Casio Prizm and Graph3CE for the TI-84 Plus CE, I know how labyrinthine symbolic and even non-symbolic EOS code can quickly get without lots of pre-planning!
I can really see that now, I barely planned anything for this, which is probably why it is such a mess.

Edit by Merth: consolidate double post
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement