Making: math interpreter. Need to fix printf %f

This commit is contained in:
xamidev
2024-08-06 13:43:01 +02:00
parent f05347f73b
commit fc17e5eade
8 changed files with 393 additions and 53 deletions

Binary file not shown.

View File

@@ -39,7 +39,6 @@ int kmain(int retvalue)
timer_install(); timer_install();
keyboard_install(); keyboard_install();
shell_install(); shell_install();
return retvalue; return retvalue;

View File

@@ -21,7 +21,7 @@ void shell_install()
} }
else if (strcmp(input_buffer, "help") == 0) else if (strcmp(input_buffer, "help") == 0)
{ {
printf("help\tpanic\twords\tprimes\trainbow\tclear\n"); printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\n");
} }
else if (strcmp(input_buffer, "panic") == 0) else if (strcmp(input_buffer, "panic") == 0)
{ {
@@ -43,6 +43,10 @@ void shell_install()
{ {
program_clear(); program_clear();
} }
else if (strcmp(input_buffer, "math") == 0)
{
program_math();
}
else { else {
printf("Unknown command %s\n", input_buffer); printf("Unknown command %s\n", input_buffer);
} }

13
src/libc/ctype.c Normal file
View File

@@ -0,0 +1,13 @@
#include "stdint.h"
bool isdigit(char c)
{
return c >= '0' && c <= '9';
}
bool isspace(char c)
{
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
}

9
src/libc/ctype.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef CTYPE_H
#define CTYPE_H
#include "stdint.h"
bool isdigit(char c);
bool isspace(char c);
#endif

View File

@@ -176,6 +176,50 @@ void colorputs(const char* str, unsigned int color)
} }
} }
// double to string for printf
void dtostrf(double val, char *buffer, int precision)
{
int whole_part = (int)val;
double fractional_part = val - whole_part;
if (fractional_part < 0) fractional_part = -fractional_part;
char *start = buffer;
if (whole_part == 0)
{
*buffer++ = '0';
}
else
{
if (whole_part < 0)
{
*buffer++ = '-';
whole_part = -whole_part;
}
char temp[32];
int pos = 0;
while (whole_part > 0)
{
temp[pos++] = '0' + (whole_part % 10);
whole_part /= 10;
}
while (pos > 0)
{
*buffer++ = temp[--pos];
}
}
*buffer++ = '.';
for (int i = 0; i < precision; i++)
{
fractional_part *= 10;
int digit = (int)fractional_part;
*buffer++ = '0' + digit;
fractional_part -= digit;
}
*buffer = '\0';
}
void printf(const char* fmt, ...) void printf(const char* fmt, ...)
{ {
int* argp = (int*) &fmt; int* argp = (int*) &fmt;
@@ -188,52 +232,52 @@ void printf(const char* fmt, ...)
while (*fmt) while (*fmt)
{ {
switch(state) { switch(state) {
case PRINTF_STATE_START: case PRINTF_STATE_START:
if (*fmt == '%') if (*fmt == '%')
{ {
state = PRINTF_STATE_LENGTH; state = PRINTF_STATE_LENGTH;
} }
else { else {
putc(*fmt); putc(*fmt);
} }
break; break;
case PRINTF_STATE_LENGTH: case PRINTF_STATE_LENGTH:
if (*fmt == 'h') if (*fmt == 'h')
{ {
length = PRINTF_LENGTH_SHORT; length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_SHORT; state = PRINTF_STATE_SHORT;
} }
else if (*fmt == 'l') else if (*fmt == 'l')
{ {
length = PRINTF_LENGTH_LONG; length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LONG; state = PRINTF_STATE_LONG;
} }
else { else {
goto PRINTF_STATE_SPEC_; goto PRINTF_STATE_SPEC_;
} }
break; break;
case PRINTF_STATE_SHORT: case PRINTF_STATE_SHORT:
if (*fmt == 'h') if (*fmt == 'h')
{ {
length = PRINTF_LENGTH_SHORT_SHORT; length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC; state = PRINTF_STATE_SPEC;
} }
else { else {
goto PRINTF_STATE_SPEC_; goto PRINTF_STATE_SPEC_;
} }
break; break;
case PRINTF_STATE_LONG: case PRINTF_STATE_LONG:
if (*fmt == 'l') if (*fmt == 'l')
{ {
length = PRINTF_LENGTH_LONG_LONG; length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC; state = PRINTF_STATE_SPEC;
} }
else { else {
goto PRINTF_STATE_SPEC_; goto PRINTF_STATE_SPEC_;
} }
break; break;
case PRINTF_STATE_SPEC: case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_: PRINTF_STATE_SPEC_:
switch(*fmt) switch(*fmt)
{ {
case 'c': case 'c':
@@ -270,14 +314,24 @@ void printf(const char* fmt, ...)
sign = false; sign = false;
argp = printf_number(argp, length, sign, radix); argp = printf_number(argp, length, sign, radix);
break; break;
case 'f': {
// Handle floating-point numbers
double* dargp = (double*)argp;
double d = *(double*)dargp;
char buffer[64];
dtostrf(d, buffer, 6); // Default precision: 6
puts(buffer);
argp += 2; // Incrementing by 2 to move past the double argument
break;
}
default: default:
break; break;
} }
state = PRINTF_STATE_START; state = PRINTF_STATE_START;
length = PRINTF_LENGTH_START; length = PRINTF_LENGTH_START;
radix = 10; radix = 10;
sign = false; sign = false;
break; break;
} }
fmt++; fmt++;
} }

260
src/programs/math.c Normal file
View File

@@ -0,0 +1,260 @@
// Math expression lexer and parser
#include "../libc/stdint.h"
#include "../kernel/system.h"
#include "../libc/stdio.h"
#include "../libc/ctype.h"
#define BUFFER_SIZE 256
typedef enum
{
TOKEN_NUMBER,
TOKEN_PLUS,
TOKEN_MINUS,
TOKEN_MULTIPLY,
TOKEN_DIVIDE,
TOKEN_LPAREN,
TOKEN_RPAREN,
TOKEN_END
} TokenType;
typedef struct
{
TokenType type;
double value;
} Token;
typedef struct
{
const char *text;
size_t pos;
Token current_token;
} Lexer;
void lexer_init(Lexer *lexer, const char *text)
{
lexer->text = text;
lexer->pos = 0;
lexer->current_token.type = TOKEN_END;
lexer->current_token.value = 0;
}
void lexer_advance(Lexer *lexer)
{
lexer->pos++;
}
char lexer_peek(const Lexer *lexer)
{
return lexer->text[lexer->pos];
}
bool lexer_is_at_end(const Lexer *lexer)
{
return lexer->text[lexer->pos] == '\0';
}
Token lexer_get_next_token(Lexer *lexer)
{
while (!lexer_is_at_end(lexer))
{
char current_char = lexer_peek(lexer);
if (isspace(current_char)) {
lexer_advance(lexer);
continue;
}
if (isdigit(current_char)) {
double value = 0;
while (isdigit(current_char))
{
value = value * 10 + (current_char - '0');
lexer_advance(lexer);
current_char = lexer_peek(lexer);
}
if (current_char == '.')
{
lexer_advance(lexer);
double decimal_place = 0.1;
while (isdigit(lexer_peek(lexer)))
{
value += decimal_place * (lexer_peek(lexer)-'0');
decimal_place *= 0.1;
lexer_advance(lexer);
}
}
lexer->current_token.type = TOKEN_NUMBER;
lexer->current_token.value = value;
//printf("NUMBER %f\n", value);
return lexer->current_token;
}
if (current_char == '+')
{
lexer_advance(lexer);
lexer->current_token.type = TOKEN_PLUS;
printf("PLUS\n");
return lexer->current_token;
}
if (current_char == '-')
{
lexer_advance(lexer);
lexer->current_token.type = TOKEN_MINUS;
printf("MINUS\n");
return lexer->current_token;
}
if (current_char == '*')
{
lexer_advance(lexer);
lexer->current_token.type = TOKEN_MULTIPLY;
printf("MULTIPLY\n");
return lexer->current_token;
}
if (current_char == '/')
{
lexer_advance(lexer);
lexer->current_token.type = TOKEN_DIVIDE;
printf("DIVIDE\n");
return lexer->current_token;
}
if (current_char == '(')
{
lexer_advance(lexer);
lexer->current_token.type = TOKEN_LPAREN;
printf("LPAREN\n");
return lexer->current_token;
}
if (current_char == ')')
{
lexer_advance(lexer);
lexer->current_token.type = TOKEN_RPAREN;
printf("RPAREN\n");
return lexer->current_token;
}
printf("Unknown character %c\n", current_char);
//shell_install();
}
lexer->current_token.type = TOKEN_END;
printf("END\n");
return lexer->current_token;
}
typedef struct
{
Lexer lexer;
Token current_token;
} Parser;
void parser_init(Parser *parser, const char *text)
{
lexer_init(&parser->lexer, text);
parser->current_token = lexer_get_next_token(&parser->lexer);
}
void parser_eat(Parser *parser, TokenType type)
{
if (parser->current_token.type == type)
{
parser->current_token = lexer_get_next_token(&parser->lexer);
} else {
printf("Unexpected token %d\n", parser->current_token.type);
//shell_install();
}
}
double parser_factor(Parser *parser);
double parser_term(Parser *parser);
double parser_expression(Parser *parser);
double parser_factor(Parser *parser)
{
Token token = parser->current_token;
if (token.type == TOKEN_NUMBER)
{
parser_eat(parser, TOKEN_NUMBER);
//printf("Factor: %f\n", token.value);
return token.value;
} else if (token.type == TOKEN_LPAREN) {
parser_eat(parser, TOKEN_LPAREN);
double result = parser_expression(parser);
parser_eat(parser, TOKEN_RPAREN);
//printf("Factor (expression): %f\n", result);
return result;
} else {
printf("Unexpected token in factor %d\n", token.type);
//shell_install();
}
return -1;
}
double parser_term(Parser *parser)
{
double result = parser_factor(parser);
//printf("Initial term: %f\n", result);
while (parser->current_token.type == TOKEN_MULTIPLY || parser->current_token.type == TOKEN_DIVIDE)
{
Token token = parser->current_token;
if (token.type == TOKEN_MULTIPLY)
{
parser_eat(parser, TOKEN_MULTIPLY);
result *= parser_factor(parser);
//printf("Term after multiply: %f\n", result);
} else if (token.type == TOKEN_DIVIDE) {
parser_eat(parser, TOKEN_DIVIDE);
result /= parser_factor(parser);
//printf("Term after divide: %f\n", result);
}
}
return result;
}
double parser_expression(Parser *parser)
{
double result = parser_term(parser);
//printf("Initial expression: %f\n", result);
while (parser->current_token.type == TOKEN_PLUS || parser->current_token.type == TOKEN_MINUS)
{
Token token = parser->current_token;
if (token.type == TOKEN_PLUS)
{
parser_eat(parser, TOKEN_PLUS);
result += parser_term(parser);
//printf("Expression after plus: %f\n", result);
} else if (token.type == TOKEN_MINUS) {
parser_eat(parser, TOKEN_MINUS);
result -= parser_term(parser);
//printf("Expression after minus: %f\n", result);
}
}
return result;
}
double parse(const char* text)
{
Parser parser;
parser_init(&parser, text);
double result = parser_expression(&parser);
//printf("Final result: %f\n", result);
return result;
}
void program_math()
{
char input_buffer[BUFFER_SIZE];
puts("Expression? ");
get_input(input_buffer, BUFFER_SIZE);
printf("Input: %s\n", input_buffer);
double result = parse(input_buffer);
printf("\n%f\n", result);
}

View File

@@ -3,6 +3,7 @@
void program_words(); void program_words();
void program_primes(); void program_primes();
void program_math();
// Misc // Misc
void program_rainbow(); void program_rainbow();