- 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
|
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
|
||||||
|
|||||||
@@ -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?
|
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
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
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 |
143
src/basic.c
143
src/basic.c
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/basic.h
20
src/basic.h
@@ -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
|
||||||
|
|||||||
18
src/conio.c
18
src/conio.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_ */
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
60
src/stdlib.c
60
src/stdlib.c
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
17
src/string.c
17
src/string.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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_ */
|
||||||
|
|||||||
@@ -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
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"
|
#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
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