Making: math interpreter. Need to fix printf %f
This commit is contained in:
Binary file not shown.
@@ -39,7 +39,6 @@ int kmain(int retvalue)
|
|||||||
|
|
||||||
timer_install();
|
timer_install();
|
||||||
keyboard_install();
|
keyboard_install();
|
||||||
|
|
||||||
shell_install();
|
shell_install();
|
||||||
|
|
||||||
return retvalue;
|
return retvalue;
|
||||||
|
|||||||
@@ -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
13
src/libc/ctype.c
Normal 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
9
src/libc/ctype.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CTYPE_H
|
||||||
|
#define CTYPE_H
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
bool isdigit(char c);
|
||||||
|
bool isspace(char c);
|
||||||
|
|
||||||
|
#endif
|
||||||
156
src/libc/stdio.c
156
src/libc/stdio.c
@@ -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
260
src/programs/math.c
Normal 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);
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user