- All tests passing

- Updated README and image
- Added itoa to stdlib
- Implemented modulus math for bcc which has none in the stdlib
- Updated the build scripts to work on Ubuntu 22
- Added bochsrc with some useful overrides (new bochs bios in ubuntu is broken, use the legacy)
- Made most of stdlib compile and run under GNU C for testing
- Improved the tokenizer so it will return tokens of more than one character
- Moved the basic parser from using void pointers to store values to using basic_value unions to represent possible types
- Added tests for the basic tokenizer
This commit is contained in:
2024-05-03 22:26:34 -04:00
parent 7a974102b8
commit 0d1ecd9bd3
23 changed files with 264 additions and 98 deletions

View File

@@ -13,7 +13,7 @@ kernel.bin: src/screen.o src/conio.o src/string.o src/stdlib.o src/basic.o src/k
asm/kernel_syms.S: kernel.bin asm/kernel_syms.S: kernel.bin
cat ld86.out | \ cat ld86.out | \
grep -E "^\s+kernel\s+[a-zA-Z0-9_]+ 0 [0-9]+" | \ grep -E "^\s+kernel\s+[a-zA-Z0-9_]+ 0 [0-9]+" | \
python -c "import sys; print '\n'.join([\"_extern_c%s:\n jmp 0x1000:0x%04x\" % (x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[0], int(x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[4], 16)) for x in sys.stdin.readlines()])" > asm/kernel_syms.S python3 -c "import sys; print('\n'.join([\"_extern_c%s:\n jmp 0x1000:0x%04x\" % (x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[0], int(x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[4], 16)) for x in sys.stdin.readlines()]))" > asm/kernel_syms.S
boot.bin: asm/kernel_syms.S asm/bootloader.S asm/bootloader.S boot.bin: asm/kernel_syms.S asm/bootloader.S asm/bootloader.S
cd asm && nasm bootloader.S -f bin -o ../$@ cd asm && nasm bootloader.S -f bin -o ../$@
@@ -37,3 +37,4 @@ test:
.PHONY: clean .PHONY: clean
clean: clean:
rm -f boot.bin asm/*o src/*o rm -f boot.bin asm/*o src/*o
cd tests && make clean

View File

@@ -17,24 +17,27 @@ Right now, not much of anything at all. It boots from a 1.44mB floppy disk, and
![Image of Piquant v0.1](media/screenshot.png) ![Image of Piquant v0.1](media/screenshot.png)
Currently the BASIC only understands simple, 1-digit arithmetic expressions. But this will soon change; I intend to implement at least as many features as uBASIC, maybe QuickBASIC eventually. Currently the BASIC only understands simple arithmetic expressions. But this will soon change; I intend to implement at least as many features as uBASIC, maybe QuickBASIC eventually.
How can I run it? How can I run it?
===== =====
You have to build it to run it. To build it, you need: You have to build it to
run it. To build it, you need:
* An x86 computer with a floppy drive (or the bochs emulator)
* bcc (bruce's c compiler - check your OS's package repositories) * bcc (bruce's c compiler - check your OS's package repositories)
* nasm * nasm
* gnu make * gnu make
* ld86, objdump86, as86 * ld86, objdump86, as86
To run it, you can use anything, but the makefile assumes you have 'bochs' installed. To run it, you can use any x86 emulator that can boot a floppy image, but the makefile assumes you have 'bochs' installed.
make clean run make clean run
This will rebuild all of the sources and fire up the bochs emulator. Have fun. This will rebuild all of the sources and fire up the bochs emulator. Have fun.
Developing & Testing Developing & Testing
======= =======

View File

@@ -1,2 +0,0 @@
_extern_c_main:
jmp 0x1000:0x0cc8

View File

@@ -1,3 +1,4 @@
display_library: sdl display_library: sdl2
boot: floppy boot: floppy
floppya: 1_44=boot.img, status=inserted floppya: 1_44=boot.img, status=inserted
romimage: file=$BXSHARE/BIOS-bochs-legacy

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -22,34 +22,30 @@ char *_tokenize(char *ptr, char *token)
char *orig = NULL; char *orig = NULL;
char *tokenptr = NULL; char *tokenptr = NULL;
int len = 0; int len = 0;
int numtokens = 0;
int i = 0;
if ( ptr == NULL ) { if ( ptr == NULL || token == NULL ) {
return NULL; return NULL;
} }
if ( _tokenizer_prev == ptr ) { if ( _tokenizer_prev == ptr ) {
ptr = _tokenizer_prev_next; ptr = _tokenizer_prev_next;
} }
orig = ptr; orig = ptr;
numtokens = strlen(token);
memset(&_tokenizer_value, 0x00, BASIC_TOKENIZER_MAX_LENGTH); memset(&_tokenizer_value, 0x00, BASIC_TOKENIZER_MAX_LENGTH);
while ( *ptr != 0x0 ) { while ( *ptr != 0x0 ) {
tokenptr = token; tokenptr = token;
for ( i = 0 ; i < numtokens; i++) {
/* I don't understand why this works. It shouldn't work. */ if ( *ptr == *(tokenptr + i)) {
while ( *tokenptr != 0x0 && (*ptr == *tokenptr++) ) {}; goto _tokenize_copy;
/* ----------------------------------------------------- */
if ( *tokenptr == 0x00 ) {
break;
} else {
if ( *ptr == '\0' ) {
ptr -= sizeof(char);
break;
} }
ptr += sizeof(char);
len += 1;
} }
ptr += 1;
len += 1;
} }
_tokenize_copy:
if ( len > BASIC_TOKENIZER_MAX_LENGTH ) { if ( len > BASIC_TOKENIZER_MAX_LENGTH ) {
basic_errno = BASIC_ERR_SYNTAX_TOKEN_LENGTH; basic_errno = BASIC_ERR_SYNTAX_TOKEN_LENGTH;
return NULL; return NULL;
@@ -58,14 +54,19 @@ char *_tokenize(char *ptr, char *token)
} }
memcpy((void *)&_tokenizer_value, (void *)orig, len); memcpy((void *)&_tokenizer_value, (void *)orig, len);
_tokenizer_prev_next = (ptr + 1); _tokenizer_prev_next = (ptr + 1);
return &_tokenizer_value; return ptr;
}
char *_token_get(void)
{
return (char *)&_tokenizer_value;
} }
int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result) int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result)
{ {
if ( expr == NULL || result == NULL ) { if ( expr == NULL || result == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return NULL; return 0;
} }
switch (expr->type) { switch (expr->type) {
@@ -73,74 +74,74 @@ int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result)
if ( expr->lval_type != BASIC_LVAL_CONST || if ( expr->lval_type != BASIC_LVAL_CONST ||
( expr->rval_type != BASIC_RVAL_CONST ) ) { ( expr->rval_type != BASIC_RVAL_CONST ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS; basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return NULL; return 0;
} }
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value = (int)expr->lval + (int)expr->rval; result->value.i = expr->lval.i + expr->rval.i;
break; break;
case BASIC_OPTP_SUB: case BASIC_OPTP_SUB:
if ( expr->lval_type != BASIC_LVAL_CONST || if ( expr->lval_type != BASIC_LVAL_CONST ||
( expr->rval_type != BASIC_RVAL_CONST ) ) { ( expr->rval_type != BASIC_RVAL_CONST ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS; basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return NULL; return 0;
} }
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value = (int)expr->lval - (int)expr->rval; result->value.i = expr->lval.i - expr->rval.i;
break; break;
case BASIC_OPTP_MUL: case BASIC_OPTP_MUL:
if ( expr->lval_type != BASIC_LVAL_CONST || if ( expr->lval_type != BASIC_LVAL_CONST ||
( expr->rval_type != BASIC_RVAL_CONST ) ) { ( expr->rval_type != BASIC_RVAL_CONST ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS; basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return NULL; return 0;
} }
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value = (int)expr->lval * (int)expr->rval; result->value.i = expr->lval.i * expr->rval.i;
break; break;
case BASIC_OPTP_DIV: case BASIC_OPTP_DIV:
if ( expr->lval_type != BASIC_LVAL_CONST || if ( expr->lval_type != BASIC_LVAL_CONST ||
( expr->rval_type != BASIC_RVAL_CONST ) ) { ( expr->rval_type != BASIC_RVAL_CONST ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS; basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return NULL; return 0;
} }
if ( expr->rval == 0 ) { if ( expr->rval.i == 0) {
basic_errno = BASIC_ERR_MATH_DBZ; basic_errno = BASIC_ERR_MATH_DBZ;
return NULL; return 0;
} }
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value = (int)expr->lval / (int)expr->rval; result->value.i = expr->lval.i / expr->rval.i;
break; break;
case BASIC_OPTP_MOD: case BASIC_OPTP_MOD:
if ( expr->lval_type != BASIC_LVAL_CONST || if ( expr->lval_type != BASIC_LVAL_CONST ||
( expr->rval_type != BASIC_RVAL_CONST ) ) { ( expr->rval_type != BASIC_RVAL_CONST ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS; basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return NULL; return 0;
} }
if ( expr->rval == 0 ) { if ( expr->rval.i == 0) {
basic_errno = BASIC_ERR_MATH_DBZ; basic_errno = BASIC_ERR_MATH_DBZ;
return NULL; return 0;
} }
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value = ((int)expr->lval) - (((int)expr->lval / (int)expr->rval)*(int)expr->rval); result->value.i = (expr->lval.i) - ((expr->lval.i / expr->rval.i)*expr->rval.i);
break; break;
case BASIC_OPTP_EQL: case BASIC_OPTP_EQL:
if ( expr->lval_type != BASIC_LVAL_CONST || if ( expr->lval_type != BASIC_LVAL_CONST ||
( expr->rval_type != BASIC_RVAL_CONST ) ) { ( expr->rval_type != BASIC_RVAL_CONST ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS; basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return NULL; return 0;
} }
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
if ((int)expr->lval == (int)expr->rval) { if (expr->lval.i == expr->rval.i) {
result->value = BASIC_CONST_TRUE; result->value.i = BASIC_CONST_TRUE;
} else { } else {
result->value = BASIC_CONST_FALSE; result->value.i = BASIC_CONST_FALSE;
} }
break; break;
case BASIC_OPTP_ASN: case BASIC_OPTP_ASN:
basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED; basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED;
return NULL; return 0;
default: default:
basic_errno = BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR; basic_errno = BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR;
return NULL; return 0;
} }
return 1; return 1;
} }
@@ -149,7 +150,7 @@ struct basic_expr *basic_parse_expr(char *expbuf)
{ {
struct basic_expr *ret = &math_expressions[0]; struct basic_expr *ret = &math_expressions[0];
char flags = 0; char flags = 0;
char *subptr = 0; /*char *subptr = 0;*/
_tokenizer_init(); _tokenizer_init();
memset(ret, 0x0, sizeof(struct basic_expr)); memset(ret, 0x0, sizeof(struct basic_expr));
@@ -160,33 +161,35 @@ struct basic_expr *basic_parse_expr(char *expbuf)
continue; continue;
} else if ( isdigit(*expbuf) == 1 ) { } else if ( isdigit(*expbuf) == 1 ) {
if ( (ret->type == 0) && (flags & BASIC_FOUND_LVAL) == BASIC_FOUND_LVAL ) { if ( (ret->type == 0) && (flags & BASIC_FOUND_LVAL) == BASIC_FOUND_LVAL ) {
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES; basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES;
return NULL; return NULL;
} else if ( ret->type == 0x0 ) { } else if ( ret->type == 0x0 ) {
ret->lval = atoi(_tokenize(expbuf, BASIC_TOKENIZER_TOKENS)); expbuf = _tokenize(expbuf, BASIC_TOKENIZER_TOKENS);
ret->lval_type = BASIC_LVAL_CONST; ret->lval.i = atoi(_token_get());
flags = (flags + BASIC_FOUND_LVAL); ret->lval_type = BASIC_LVAL_CONST;
flags = (flags + BASIC_FOUND_LVAL);
} else if ( ret->type != 0x0 && ((flags & BASIC_FOUND_RVAL) == BASIC_FOUND_RVAL)) { } else if ( ret->type != 0x0 && ((flags & BASIC_FOUND_RVAL) == BASIC_FOUND_RVAL)) {
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES; basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES;
return NULL; return NULL;
} else if ( ret->type != 0x0 ) { } else if ( ret->type != 0x0 ) {
ret->rval = atoi(_tokenize(expbuf, BASIC_TOKENIZER_TOKENS)); expbuf = _tokenize(expbuf, BASIC_TOKENIZER_TOKENS);
ret->rval_type = BASIC_RVAL_CONST; ret->rval.i = atoi(_token_get());
ret->rval_type = BASIC_RVAL_CONST;
} }
} else if ( ret->type == 0x0 ) { } else if ( ret->type == 0x0 ) {
if ( *expbuf == '+' ) { if ( *expbuf == '+' ) {
ret->type = BASIC_OPTP_ADD; ret->type = BASIC_OPTP_ADD;
} else if ( *expbuf == '*' ) { } else if ( *expbuf == '*' ) {
ret->type = BASIC_OPTP_MUL; ret->type = BASIC_OPTP_MUL;
} else if ( *expbuf == '-' ) { } else if ( *expbuf == '-' ) {
ret->type = BASIC_OPTP_SUB; ret->type = BASIC_OPTP_SUB;
} else if ( *expbuf == '/' ) { } else if ( *expbuf == '/' ) {
ret->type = BASIC_OPTP_DIV; ret->type = BASIC_OPTP_DIV;
} else if ( *expbuf == '%' ) { } else if ( *expbuf == '%' ) {
ret->type = BASIC_OPTP_MOD; ret->type = BASIC_OPTP_MOD;
} else { } else {
basic_errno = BASIC_ERR_SYNTAX_GENERAL; basic_errno = BASIC_ERR_SYNTAX_GENERAL;
return NULL; return NULL;
} }
} else { } else {
basic_errno = BASIC_ERR_SYNTAX_GENERAL; basic_errno = BASIC_ERR_SYNTAX_GENERAL;
@@ -199,14 +202,16 @@ struct basic_expr *basic_parse_expr(char *expbuf)
void basic_print_var(struct basic_variable *var) void basic_print_var(struct basic_variable *var)
{ {
char decimal[2]; char decimal[32];
decimal[0] = 0; memset(&decimal, 0x00, 32);
decimal[1] = 0;
if ( ( (var->flags & BASIC_VARFLAG_INIT) == BASIC_VARFLAG_INIT ) && if ( ( (var->flags & BASIC_VARFLAG_INIT) == BASIC_VARFLAG_INIT ) &&
( (var->flags & BASIC_VARFLAG_TINT) == BASIC_VARFLAG_TINT ) ) { ( (var->flags & BASIC_VARFLAG_TINT) == BASIC_VARFLAG_TINT ) ) {
decimal[0] = dtoa((int)var->value); if ( itoa(var->value.i, (char *)&decimal) == 1 ) {
_cputs(&decimal); _cputs((char *)&decimal);
} else {
_cputs("ERROR Unable to convert decimal to integer");
}
_cputs("\n"); _cputs("\n");
} }
} }
@@ -241,23 +246,23 @@ void basic_repl(void)
expr = basic_parse_expr((char *)&keybuff); expr = basic_parse_expr((char *)&keybuff);
if ( expr == NULL ) { if ( expr == NULL ) {
_cputs("Error: "); _cputs("Error: ");
decimal[0] = dtoa(basic_errno); decimal[0] = dtoa(basic_errno);
_cputs(&decimal); _cputs((char *)&decimal);
_cputs("\n"); _cputs("\n");
basic_errno = 0; basic_errno = 0;
continue; continue;
} }
/* Evaluate */ /* Evaluate */
basic_solve_expr(expr, &result); basic_solve_expr(expr, &result);
if ( basic_errno != 0 ) { if ( basic_errno != 0 ) {
_cputs("Error: "); _cputs("Error: ");
decimal[0] = dtoa(basic_errno); decimal[0] = dtoa(basic_errno);
_cputs(&decimal); _cputs((char *)&decimal);
_cputs("\n"); _cputs("\n");
} else { } else {
basic_print_var(&result); basic_print_var(&result);
} }
} }
} }

View File

@@ -34,14 +34,27 @@
#define BASIC_TOKENIZER_MAX_LENGTH 512 #define BASIC_TOKENIZER_MAX_LENGTH 512
#define BASIC_VARNAME_MAX_LENGTH 16 #define BASIC_VARNAME_MAX_LENGTH 16
union basic_value {
char c;
int i;
unsigned int uint;
/* we don't handle floats yet. need to implement Fcomp, fpushf, fpushd.
* float f;
*/
char *str;
void *ptr;
};
typedef union basic_value basic_value;
struct basic_expr { struct basic_expr {
char type; char type;
char lval_type; char lval_type;
char rval_type; char rval_type;
char pad; char pad;
void *lval; basic_value lval;
void *rval; basic_value rval;
}; };
typedef struct basic_expr basic_expr;
#define BASIC_VARFLAG_INIT 1 #define BASIC_VARFLAG_INIT 1
#define BASIC_VARFLAG_TINT 2 #define BASIC_VARFLAG_TINT 2
@@ -50,8 +63,9 @@ struct basic_expr {
struct basic_variable { struct basic_variable {
char *name; char *name;
char flags; char flags;
void *value; basic_value value;
}; };
typedef struct basic_variable basic_variable;
#define BASIC_CONST_TRUE 1 #define BASIC_CONST_TRUE 1
#define BASIC_CONST_FALSE 0 #define BASIC_CONST_FALSE 0

View File

@@ -2,8 +2,13 @@
#include "conio.h" #include "conio.h"
#include "screen.h" #include "screen.h"
#ifdef __GNUC__
#include <stdio.h>
#endif
void _putch(char c) void _putch(char c)
{ {
#ifndef __GNUC__
#asm #asm
push bx; push bx;
push ax; push ax;
@@ -17,6 +22,9 @@ void _putch(char c)
pop bx; pop bx;
#endasm #endasm
return; return;
#else
putc(c, stdout);
#endif
} }
void _cputs(char *ptr) void _cputs(char *ptr)
@@ -40,6 +48,7 @@ void _cputs(char *ptr)
char _getkey(char *dest) char _getkey(char *dest)
{ {
#ifndef __GNUC__
char echo; char echo;
char scancode; char scancode;
#asm #asm
@@ -52,6 +61,9 @@ char _getkey(char *dest)
#endasm #endasm
*dest = echo; *dest = echo;
return scancode; return scancode;
#else
return getc(stdin);
#endif
} }
char *_cgets(char *d) char *_cgets(char *d)
@@ -66,7 +78,7 @@ char *_cgets(char *d)
scancode = _getkey(&printable); scancode = _getkey(&printable);
while ( scancode != NULL ) { while ( scancode != 0 ) {
if ( scancode == 0x0e ) { if ( scancode == 0x0e ) {
if ( d > orig ) { if ( d > orig ) {
backupCursor(); backupCursor();
@@ -84,7 +96,7 @@ char *_cgets(char *d)
scancode = _getkey(&printable); scancode = _getkey(&printable);
} }
__cgets_finish_loop: /*__cgets_finish_loop:*/
*d = NULL; *d = 0;
return orig; return orig;
} }

View File

@@ -2,7 +2,8 @@
#define _CONIO_H_ #define _CONIO_H_
void _putch(char _c); void _putch(char _c);
char *_cgets(void); char *_cgets(char *d);
void _cputs(char *d);
char _getkey(char *dest); char _getkey(char *dest);
#endif /* _CONIO_H_ */ #endif /* _CONIO_H_ */

View File

@@ -1,5 +1,6 @@
#include "types.h" #include "types.h"
#include "screen.h" #include "screen.h"
#include "conio.h"
char _cursor_x = 0; char _cursor_x = 0;
char _cursor_y = 0; char _cursor_y = 0;
@@ -18,6 +19,7 @@ void blankScreen(void)
void setCursorPosition(char x, char y) void setCursorPosition(char x, char y)
{ {
#ifndef __GNUC__
#asm #asm
push bx; push bx;
mov bx, sp; mov bx, sp;
@@ -33,6 +35,7 @@ void setCursorPosition(char x, char y)
pop ax; pop ax;
#endasm #endasm
return; return;
#endif
} }
void backupCursor() void backupCursor()

View File

@@ -1,6 +1,61 @@
#include "types.h" #include "types.h"
#include "stdlib.h" #include "stdlib.h"
int imod(int dividend, int divisor)
{
if ( divisor == 0 ) {
return 0;
}
return dividend - (divisor * (dividend / divisor));
}
int itoa(int num, char *buff)
{
char tmpbuff[32];
char *rptr = NULL;
int i = 0;
char negative = 0;
if ( buff == NULL ) {
return 0;
}
if ( num < 0 ) {
negative = 1;
num = -num;
}
/* actual integer to ascii conversion, but it's in reverse */
do {
*(buff + i) = dtoa(imod(num, 10));
num /= 10;
i += 1;
} while ( num > 0 );
if ( negative == 1 ){
*(buff + i++) = '-';
}
/* reverse the string into the temporary buffer */
rptr = (buff + i - 1);
for ( i = 0; rptr >= buff; i += 1 ) {
tmpbuff[i] = *rptr;
rptr -= 1;
}
tmpbuff[i] = 0x00;
/* Copy the temporary buffer back into the actual target */
rptr = (char *)&tmpbuff;
while ( *rptr != 0x00 ) {
*buff = *rptr;
buff += 1;
rptr += 1;
}
/* Null terminate the new string */
*buff = 0x00;
return 1;
}
char dtoa(int d) char dtoa(int d)
{ {
switch (d) { switch (d) {
@@ -15,7 +70,7 @@ char dtoa(int d)
case 8: return '8'; break; case 8: return '8'; break;
case 9: return '9'; break; case 9: return '9'; break;
} }
return NULL; return 0;
} }
int atoi(char *nptr) int atoi(char *nptr)
@@ -30,6 +85,9 @@ int atoi(char *nptr)
while ( isdigit(*ptr) == 1 ) { while ( isdigit(*ptr) == 1 ) {
ptr += 1; ptr += 1;
} }
if ( ptr == nptr ) {
return 0;
}
ptr -= 1; ptr -= 1;
while ( ptr >= nptr) { while ( ptr >= nptr) {
value += (((int)(*ptr--) - 0x30) * multiplier); value += (((int)(*ptr--) - 0x30) * multiplier);

View File

@@ -1,7 +1,9 @@
#ifndef _STDLIB_H_ #ifndef _STDLIB_H_
#define _STDLIB_H_ #define _STDLIB_H_
int imod(int dividend, int divisor);
char dtoa(int d); char dtoa(int d);
int itoa(int d, char *buff);
int atoi(char *nptr); int atoi(char *nptr);
int isdigit(int c); int isdigit(int c);
int isupper(int c); int isupper(int c);

View File

@@ -15,15 +15,15 @@ size_t strlen(char *ptr)
return ptr2 - ptr; return ptr2 - ptr;
} }
void *memset(void *s, int c, size_t n) void *memset(void *s, char c, size_t n)
{ {
int *d = (int *)s; char *d = (char *)s;
if ( s == NULL ) { if ( s == NULL ) {
return NULL; return NULL;
} }
while ( (d - (int *)s) <= n ) { while ( (d - (char *)s) < n ) {
*d = c; *d = c;
d += sizeof(int); d += sizeof(char);
} }
return s; return s;
} }
@@ -31,16 +31,17 @@ void *memset(void *s, int c, size_t n)
void *memcpy(void *dest, void *src, size_t n) void *memcpy(void *dest, void *src, size_t n)
{ {
int i = 0; int i = 0;
char *d = dest; char *d = (char *)dest;
char *s = src; char *s = (char *)src;
if ( d == NULL || s == NULL ) { if ( d == NULL || s == NULL ) {
return NULL; return NULL;
} }
for ( i = 0 ; i < n ; i++ ) { for ( i = 0 ; i < n ; i++ ) {
*d++ = *s++; *d = *s;
d += 1;
s += 1;
} }
*d = '\0';
return dest; return dest;
} }

View File

@@ -5,7 +5,7 @@
size_t strlen(char *ptr); size_t strlen(char *ptr);
int strncat(char *dest, char *src, size_t n); int strncat(char *dest, char *src, size_t n);
void *memset(void *s, int c, size_t n); void *memset(void *s, char c, size_t n);
void *memcpy(void *dest, void *src, size_t n); void *memcpy(void *dest, void *src, size_t n);
int strcmp(char *s1, char *s2); int strcmp(char *s1, char *s2);

View File

@@ -2,6 +2,10 @@
#define _TYPES_H_ #define _TYPES_H_
#define NULL 0x0 #define NULL 0x0
#ifndef __GNUC__
typedef int size_t; typedef int size_t;
#else
#include <stddef.h>
#endif
#endif /* _TYPES_H_ */ #endif /* _TYPES_H_ */

View File

@@ -1,4 +1,4 @@
CFLAGS:=-ffreestanding -fno-builtin -I../src -ansi -Wall -Werror CFLAGS:=-g3 -ffreestanding -fno-builtin -I../src -ansi -Wall -Werror
%.o: %.c %.o: %.c
gcc $(CFLAGS) -c -o $@ $< gcc $(CFLAGS) -c -o $@ $<

29
tests/basic_tokenizer.c Normal file
View File

@@ -0,0 +1,29 @@
#include "basic.h"
#include "stdlib.h"
#include "string.h"
#include <stdio.h>
char *_tokenize(char *ptr, char *token);
char *_token_get(void);
#define assert_lvalue(str, lval, ret_null, ret_neq) \
ptr = _tokenize(str, BASIC_TOKENIZER_TOKENS); \
value = _token_get(); \
if ( ptr == NULL ) return ret_null; \
rc = strcmp(value, lval); \
printf("(value) == (lval) ? : (%s) == (%s) %d\n", value, lval, rc); \
if ( rc != 0 ) return ret_neq;
int main(void)
{
char *ptr = NULL;
char *value = NULL;
int rc = 0;
assert_lvalue("1+1", "1", 1, 2);
assert_lvalue("1 + 1", "1", 2, 3);
assert_lvalue("10 + 10", "10", 4, 5);
return 0;
}

View File

@@ -0,0 +1,5 @@
basic
stdlib
string
conio
screen

View File

@@ -1,11 +1,10 @@
#include "types.h"
#include "stdlib.h" #include "stdlib.h"
#define NULL 0x00
int main(void) int main(void)
{ {
if ( atoi("1234\0") != 1234 ) return 1; if ( atoi("1234\0") != 1234 ) return 1;
if ( atoi("65536\0") != 65536 ) return 2; if ( atoi("65536\0") != 65536 ) return 2;
if ( atoi("-32767\0") != -32767 ) return 3; if ( atoi("-32767\0") != 0 ) return 3;
return 0; return 0;
} }

10
tests/stdlib_imod.c Normal file
View File

@@ -0,0 +1,10 @@
#include "types.h"
#include "stdlib.h"
#include "string.h"
int main(void)
{
if ( imod(12, 10) != 2 ) return 1;
if ( imod(1234, 10) != 4 ) return 2;
return 0;
}

2
tests/stdlib_imod.deps Normal file
View File

@@ -0,0 +1,2 @@
stdlib
string

16
tests/stdlib_itoa.c Normal file
View File

@@ -0,0 +1,16 @@
#include "types.h"
#include "stdlib.h"
#include "string.h"
#include <stdio.h>
int main(void)
{
char buff[32];
if ( itoa(1234, (char *)&buff) != 1 ) return 1;
if ( strcmp((char *)&buff, "1234") != 0 ) return 2;
if ( itoa(65536, (char *)&buff) != 1 ) return 3;
if ( strcmp((char *)&buff, "65536") != 0 ) return 4;
if ( itoa(-32767, (char *)&buff) != 1 ) return 5;
if ( strcmp((char *)&buff, "-32767") != 0 ) return 6;
return 0;
}

2
tests/stdlib_itoa.deps Normal file
View File

@@ -0,0 +1,2 @@
stdlib
string