- 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

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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_ */

View File

@@ -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()

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

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