- 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:
3
Makefile
3
Makefile
@@ -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
|
||||
cat ld86.out | \
|
||||
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
|
||||
cd asm && nasm bootloader.S -f bin -o ../$@
|
||||
@@ -37,3 +37,4 @@ test:
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f boot.bin asm/*o src/*o
|
||||
cd tests && make clean
|
||||
|
||||
@@ -17,24 +17,27 @@ Right now, not much of anything at all. It boots from a 1.44mB floppy disk, and
|
||||
|
||||

|
||||
|
||||
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?
|
||||
=====
|
||||
|
||||
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)
|
||||
* nasm
|
||||
* gnu make
|
||||
* 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
|
||||
|
||||
This will rebuild all of the sources and fire up the bochs emulator. Have fun.
|
||||
|
||||
|
||||
Developing & Testing
|
||||
=======
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
_extern_c_main:
|
||||
jmp 0x1000:0x0cc8
|
||||
3
bochsrc
3
bochsrc
@@ -1,3 +1,4 @@
|
||||
display_library: sdl
|
||||
display_library: sdl2
|
||||
boot: floppy
|
||||
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 |
145
src/basic.c
145
src/basic.c
@@ -22,34 +22,30 @@ char *_tokenize(char *ptr, char *token)
|
||||
char *orig = NULL;
|
||||
char *tokenptr = NULL;
|
||||
int len = 0;
|
||||
int numtokens = 0;
|
||||
int i = 0;
|
||||
|
||||
if ( ptr == NULL ) {
|
||||
if ( ptr == NULL || token == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
if ( _tokenizer_prev == ptr ) {
|
||||
ptr = _tokenizer_prev_next;
|
||||
}
|
||||
orig = ptr;
|
||||
numtokens = strlen(token);
|
||||
|
||||
memset(&_tokenizer_value, 0x00, BASIC_TOKENIZER_MAX_LENGTH);
|
||||
while ( *ptr != 0x0 ) {
|
||||
tokenptr = token;
|
||||
|
||||
/* I don't understand why this works. It shouldn't work. */
|
||||
while ( *tokenptr != 0x0 && (*ptr == *tokenptr++) ) {};
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
if ( *tokenptr == 0x00 ) {
|
||||
break;
|
||||
} else {
|
||||
if ( *ptr == '\0' ) {
|
||||
ptr -= sizeof(char);
|
||||
break;
|
||||
}
|
||||
ptr += sizeof(char);
|
||||
len += 1;
|
||||
for ( i = 0 ; i < numtokens; i++) {
|
||||
if ( *ptr == *(tokenptr + i)) {
|
||||
goto _tokenize_copy;
|
||||
}
|
||||
}
|
||||
ptr += 1;
|
||||
len += 1;
|
||||
}
|
||||
_tokenize_copy:
|
||||
if ( len > BASIC_TOKENIZER_MAX_LENGTH ) {
|
||||
basic_errno = BASIC_ERR_SYNTAX_TOKEN_LENGTH;
|
||||
return NULL;
|
||||
@@ -58,14 +54,19 @@ char *_tokenize(char *ptr, char *token)
|
||||
}
|
||||
memcpy((void *)&_tokenizer_value, (void *)orig, len);
|
||||
_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)
|
||||
{
|
||||
if ( expr == NULL || result == NULL ) {
|
||||
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 ||
|
||||
( expr->rval_type != BASIC_RVAL_CONST ) ) {
|
||||
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
case BASIC_OPTP_SUB:
|
||||
if ( expr->lval_type != BASIC_LVAL_CONST ||
|
||||
( expr->rval_type != BASIC_RVAL_CONST ) ) {
|
||||
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
case BASIC_OPTP_MUL:
|
||||
if ( expr->lval_type != BASIC_LVAL_CONST ||
|
||||
( expr->rval_type != BASIC_RVAL_CONST ) ) {
|
||||
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
case BASIC_OPTP_DIV:
|
||||
if ( expr->lval_type != BASIC_LVAL_CONST ||
|
||||
( expr->rval_type != BASIC_RVAL_CONST ) ) {
|
||||
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;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
case BASIC_OPTP_MOD:
|
||||
if ( expr->lval_type != BASIC_LVAL_CONST ||
|
||||
( expr->rval_type != BASIC_RVAL_CONST ) ) {
|
||||
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;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
case BASIC_OPTP_EQL:
|
||||
if ( expr->lval_type != BASIC_LVAL_CONST ||
|
||||
( expr->rval_type != BASIC_RVAL_CONST ) ) {
|
||||
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
|
||||
if ((int)expr->lval == (int)expr->rval) {
|
||||
result->value = BASIC_CONST_TRUE;
|
||||
if (expr->lval.i == expr->rval.i) {
|
||||
result->value.i = BASIC_CONST_TRUE;
|
||||
} else {
|
||||
result->value = BASIC_CONST_FALSE;
|
||||
result->value.i = BASIC_CONST_FALSE;
|
||||
}
|
||||
break;
|
||||
case BASIC_OPTP_ASN:
|
||||
basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED;
|
||||
return NULL;
|
||||
return 0;
|
||||
default:
|
||||
basic_errno = BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -149,7 +150,7 @@ struct basic_expr *basic_parse_expr(char *expbuf)
|
||||
{
|
||||
struct basic_expr *ret = &math_expressions[0];
|
||||
char flags = 0;
|
||||
char *subptr = 0;
|
||||
/*char *subptr = 0;*/
|
||||
|
||||
_tokenizer_init();
|
||||
memset(ret, 0x0, sizeof(struct basic_expr));
|
||||
@@ -160,33 +161,35 @@ struct basic_expr *basic_parse_expr(char *expbuf)
|
||||
continue;
|
||||
} else if ( isdigit(*expbuf) == 1 ) {
|
||||
if ( (ret->type == 0) && (flags & BASIC_FOUND_LVAL) == BASIC_FOUND_LVAL ) {
|
||||
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES;
|
||||
return NULL;
|
||||
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES;
|
||||
return NULL;
|
||||
} else if ( ret->type == 0x0 ) {
|
||||
ret->lval = atoi(_tokenize(expbuf, BASIC_TOKENIZER_TOKENS));
|
||||
ret->lval_type = BASIC_LVAL_CONST;
|
||||
flags = (flags + BASIC_FOUND_LVAL);
|
||||
expbuf = _tokenize(expbuf, BASIC_TOKENIZER_TOKENS);
|
||||
ret->lval.i = atoi(_token_get());
|
||||
ret->lval_type = BASIC_LVAL_CONST;
|
||||
flags = (flags + BASIC_FOUND_LVAL);
|
||||
} else if ( ret->type != 0x0 && ((flags & BASIC_FOUND_RVAL) == BASIC_FOUND_RVAL)) {
|
||||
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES;
|
||||
return NULL;
|
||||
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES;
|
||||
return NULL;
|
||||
} else if ( ret->type != 0x0 ) {
|
||||
ret->rval = atoi(_tokenize(expbuf, BASIC_TOKENIZER_TOKENS));
|
||||
ret->rval_type = BASIC_RVAL_CONST;
|
||||
expbuf = _tokenize(expbuf, BASIC_TOKENIZER_TOKENS);
|
||||
ret->rval.i = atoi(_token_get());
|
||||
ret->rval_type = BASIC_RVAL_CONST;
|
||||
}
|
||||
} else if ( ret->type == 0x0 ) {
|
||||
if ( *expbuf == '+' ) {
|
||||
ret->type = BASIC_OPTP_ADD;
|
||||
ret->type = BASIC_OPTP_ADD;
|
||||
} else if ( *expbuf == '*' ) {
|
||||
ret->type = BASIC_OPTP_MUL;
|
||||
ret->type = BASIC_OPTP_MUL;
|
||||
} else if ( *expbuf == '-' ) {
|
||||
ret->type = BASIC_OPTP_SUB;
|
||||
ret->type = BASIC_OPTP_SUB;
|
||||
} else if ( *expbuf == '/' ) {
|
||||
ret->type = BASIC_OPTP_DIV;
|
||||
ret->type = BASIC_OPTP_DIV;
|
||||
} else if ( *expbuf == '%' ) {
|
||||
ret->type = BASIC_OPTP_MOD;
|
||||
ret->type = BASIC_OPTP_MOD;
|
||||
} else {
|
||||
basic_errno = BASIC_ERR_SYNTAX_GENERAL;
|
||||
return NULL;
|
||||
basic_errno = BASIC_ERR_SYNTAX_GENERAL;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
char decimal[2];
|
||||
decimal[0] = 0;
|
||||
decimal[1] = 0;
|
||||
char decimal[32];
|
||||
memset(&decimal, 0x00, 32);
|
||||
|
||||
if ( ( (var->flags & BASIC_VARFLAG_INIT) == BASIC_VARFLAG_INIT ) &&
|
||||
( (var->flags & BASIC_VARFLAG_TINT) == BASIC_VARFLAG_TINT ) ) {
|
||||
decimal[0] = dtoa((int)var->value);
|
||||
_cputs(&decimal);
|
||||
if ( itoa(var->value.i, (char *)&decimal) == 1 ) {
|
||||
_cputs((char *)&decimal);
|
||||
} else {
|
||||
_cputs("ERROR Unable to convert decimal to integer");
|
||||
}
|
||||
_cputs("\n");
|
||||
}
|
||||
}
|
||||
@@ -241,23 +246,23 @@ void basic_repl(void)
|
||||
|
||||
expr = basic_parse_expr((char *)&keybuff);
|
||||
if ( expr == NULL ) {
|
||||
_cputs("Error: ");
|
||||
decimal[0] = dtoa(basic_errno);
|
||||
_cputs(&decimal);
|
||||
_cputs("\n");
|
||||
basic_errno = 0;
|
||||
continue;
|
||||
_cputs("Error: ");
|
||||
decimal[0] = dtoa(basic_errno);
|
||||
_cputs((char *)&decimal);
|
||||
_cputs("\n");
|
||||
basic_errno = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Evaluate */
|
||||
basic_solve_expr(expr, &result);
|
||||
if ( basic_errno != 0 ) {
|
||||
_cputs("Error: ");
|
||||
decimal[0] = dtoa(basic_errno);
|
||||
_cputs(&decimal);
|
||||
_cputs("\n");
|
||||
_cputs("Error: ");
|
||||
decimal[0] = dtoa(basic_errno);
|
||||
_cputs((char *)&decimal);
|
||||
_cputs("\n");
|
||||
} else {
|
||||
basic_print_var(&result);
|
||||
basic_print_var(&result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
src/basic.h
20
src/basic.h
@@ -34,14 +34,27 @@
|
||||
#define BASIC_TOKENIZER_MAX_LENGTH 512
|
||||
#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 {
|
||||
char type;
|
||||
char lval_type;
|
||||
char rval_type;
|
||||
char pad;
|
||||
void *lval;
|
||||
void *rval;
|
||||
basic_value lval;
|
||||
basic_value rval;
|
||||
};
|
||||
typedef struct basic_expr basic_expr;
|
||||
|
||||
#define BASIC_VARFLAG_INIT 1
|
||||
#define BASIC_VARFLAG_TINT 2
|
||||
@@ -50,8 +63,9 @@ struct basic_expr {
|
||||
struct basic_variable {
|
||||
char *name;
|
||||
char flags;
|
||||
void *value;
|
||||
basic_value value;
|
||||
};
|
||||
typedef struct basic_variable basic_variable;
|
||||
|
||||
#define BASIC_CONST_TRUE 1
|
||||
#define BASIC_CONST_FALSE 0
|
||||
|
||||
18
src/conio.c
18
src/conio.c
@@ -2,8 +2,13 @@
|
||||
#include "conio.h"
|
||||
#include "screen.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
void _putch(char c)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
#asm
|
||||
push bx;
|
||||
push ax;
|
||||
@@ -17,6 +22,9 @@ void _putch(char c)
|
||||
pop bx;
|
||||
#endasm
|
||||
return;
|
||||
#else
|
||||
putc(c, stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
void _cputs(char *ptr)
|
||||
@@ -40,6 +48,7 @@ void _cputs(char *ptr)
|
||||
|
||||
char _getkey(char *dest)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
char echo;
|
||||
char scancode;
|
||||
#asm
|
||||
@@ -52,6 +61,9 @@ char _getkey(char *dest)
|
||||
#endasm
|
||||
*dest = echo;
|
||||
return scancode;
|
||||
#else
|
||||
return getc(stdin);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *_cgets(char *d)
|
||||
@@ -66,7 +78,7 @@ char *_cgets(char *d)
|
||||
|
||||
scancode = _getkey(&printable);
|
||||
|
||||
while ( scancode != NULL ) {
|
||||
while ( scancode != 0 ) {
|
||||
if ( scancode == 0x0e ) {
|
||||
if ( d > orig ) {
|
||||
backupCursor();
|
||||
@@ -84,7 +96,7 @@ char *_cgets(char *d)
|
||||
scancode = _getkey(&printable);
|
||||
}
|
||||
|
||||
__cgets_finish_loop:
|
||||
*d = NULL;
|
||||
/*__cgets_finish_loop:*/
|
||||
*d = 0;
|
||||
return orig;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#define _CONIO_H_
|
||||
|
||||
void _putch(char _c);
|
||||
char *_cgets(void);
|
||||
char *_cgets(char *d);
|
||||
void _cputs(char *d);
|
||||
char _getkey(char *dest);
|
||||
|
||||
#endif /* _CONIO_H_ */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "types.h"
|
||||
#include "screen.h"
|
||||
#include "conio.h"
|
||||
|
||||
char _cursor_x = 0;
|
||||
char _cursor_y = 0;
|
||||
@@ -18,6 +19,7 @@ void blankScreen(void)
|
||||
|
||||
void setCursorPosition(char x, char y)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
#asm
|
||||
push bx;
|
||||
mov bx, sp;
|
||||
@@ -33,6 +35,7 @@ void setCursorPosition(char x, char y)
|
||||
pop ax;
|
||||
#endasm
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
void backupCursor()
|
||||
|
||||
60
src/stdlib.c
60
src/stdlib.c
@@ -1,6 +1,61 @@
|
||||
#include "types.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)
|
||||
{
|
||||
switch (d) {
|
||||
@@ -15,7 +70,7 @@ char dtoa(int d)
|
||||
case 8: return '8'; break;
|
||||
case 9: return '9'; break;
|
||||
}
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atoi(char *nptr)
|
||||
@@ -30,6 +85,9 @@ int atoi(char *nptr)
|
||||
while ( isdigit(*ptr) == 1 ) {
|
||||
ptr += 1;
|
||||
}
|
||||
if ( ptr == nptr ) {
|
||||
return 0;
|
||||
}
|
||||
ptr -= 1;
|
||||
while ( ptr >= nptr) {
|
||||
value += (((int)(*ptr--) - 0x30) * multiplier);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef _STDLIB_H_
|
||||
#define _STDLIB_H_
|
||||
|
||||
int imod(int dividend, int divisor);
|
||||
char dtoa(int d);
|
||||
int itoa(int d, char *buff);
|
||||
int atoi(char *nptr);
|
||||
int isdigit(int c);
|
||||
int isupper(int c);
|
||||
|
||||
17
src/string.c
17
src/string.c
@@ -15,15 +15,15 @@ size_t strlen(char *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 ) {
|
||||
return NULL;
|
||||
}
|
||||
while ( (d - (int *)s) <= n ) {
|
||||
while ( (d - (char *)s) < n ) {
|
||||
*d = c;
|
||||
d += sizeof(int);
|
||||
d += sizeof(char);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -31,16 +31,17 @@ void *memset(void *s, int c, size_t n)
|
||||
void *memcpy(void *dest, void *src, size_t n)
|
||||
{
|
||||
int i = 0;
|
||||
char *d = dest;
|
||||
char *s = src;
|
||||
char *d = (char *)dest;
|
||||
char *s = (char *)src;
|
||||
|
||||
if ( d == NULL || s == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
for ( i = 0 ; i < n ; i++ ) {
|
||||
*d++ = *s++;
|
||||
*d = *s;
|
||||
d += 1;
|
||||
s += 1;
|
||||
}
|
||||
*d = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
size_t strlen(char *ptr);
|
||||
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);
|
||||
int strcmp(char *s1, char *s2);
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#define _TYPES_H_
|
||||
|
||||
#define NULL 0x0
|
||||
#ifndef __GNUC__
|
||||
typedef int size_t;
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#endif /* _TYPES_H_ */
|
||||
|
||||
@@ -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
|
||||
gcc $(CFLAGS) -c -o $@ $<
|
||||
|
||||
29
tests/basic_tokenizer.c
Normal file
29
tests/basic_tokenizer.c
Normal 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;
|
||||
}
|
||||
5
tests/basic_tokenizer.deps
Normal file
5
tests/basic_tokenizer.deps
Normal file
@@ -0,0 +1,5 @@
|
||||
basic
|
||||
stdlib
|
||||
string
|
||||
conio
|
||||
screen
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "types.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#define NULL 0x00
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if ( atoi("1234\0") != 1234 ) return 1;
|
||||
if ( atoi("65536\0") != 65536 ) return 2;
|
||||
if ( atoi("-32767\0") != -32767 ) return 3;
|
||||
if ( atoi("-32767\0") != 0 ) return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
10
tests/stdlib_imod.c
Normal file
10
tests/stdlib_imod.c
Normal 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
2
tests/stdlib_imod.deps
Normal file
@@ -0,0 +1,2 @@
|
||||
stdlib
|
||||
string
|
||||
16
tests/stdlib_itoa.c
Normal file
16
tests/stdlib_itoa.c
Normal 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
2
tests/stdlib_itoa.deps
Normal file
@@ -0,0 +1,2 @@
|
||||
stdlib
|
||||
string
|
||||
Reference in New Issue
Block a user