Compare commits

...

10 Commits

Author SHA1 Message Date
40a2de796d Updated README 2024-05-12 21:42:09 -04:00
d5d96676b1 Added a GOTO command 2024-05-12 21:39:59 -04:00
10eb159ef8 WIP Removed some debug stuff 2024-05-12 21:33:55 -04:00
683b47f245 WIP : Eff it, I left the magic memcpy in. Printing mostly works but it's still broken. Calls to _cputs and _cputsf may mysteriously fail due to some kind of memory corruption I haven't tracked down yet. This commit leaves in a bunch of commented testing code, the next commit will rip them out. 2024-05-12 21:28:27 -04:00
f2cab38cf2 WIP. Somewhere in between the init of basic_cmd_run and basic_cmd_list calls to _cputs stop working with constant character string pointers and only work with pointers off the heap. 2024-05-12 08:54:11 -04:00
0826d1946b WIP Immediate mode, printing, and listing is working, but something wierd is going on with _cputs. See the comment in basic_cmd_list. I'm tempted to throw the C away and move it all to ASM so I can have more control & awareness of what's going on. 2024-05-07 18:56:07 -04:00
06d110e28b WIP : About to rip out the old parser and solver, can't get things working the way I expect and the old code is in the way 2024-05-07 18:06:01 -04:00
bd9399e060 WIP scrolling seems to work correctly now if all you ever do is call advanceCursor() 2024-05-07 17:01:19 -04:00
5b4e0e7a0f WIP minor improvements to conio/screen for scrolling, still doesn't work reliably once we print more than 25 lines 2024-05-07 16:17:36 -04:00
559ff15dc0 WIP. Storing code in line numbers and listing is working. Added a RUN command, and refactored the line runner logic out of basic_repl into basic_run_line. The repl still works but the RUN function is busted. The parser logic is increasingly getting in the way, and the solver is not as useful as I originally thought. The original design of the datastructures and logic is getting in my way and adding confusion. I may need to try something simpler. 2024-05-07 08:08:40 -04:00
11 changed files with 255 additions and 316 deletions

View File

@@ -4,11 +4,14 @@ endif
all: boot.img kernel.bin
src/%.S: src/%.c
~/bin/bcc -ansi -0 -S -d -t $@ $<
src/%.o: src/%.c
bcc -ansi -0 -c -o $@ $<
~/bin/bcc -ansi -0 -c -o $@ $<
kernel.bin: src/screen.o src/conio.o src/string.o src/stdlib.o src/basic.o src/kernel.o
ld86 -d -M -o $@ $^ | tee ld86.out
~/bin/ld86 -d -M -L/home/andrew/lib/bcc -lbcc -o $@ $^ | tee ld86.out
asm/kernel_syms.S: kernel.bin
cat ld86.out | \

View File

@@ -13,11 +13,13 @@ Because it's fun. Don't you like to have fun? Ogre.
What does it do?
=====
Right now, not much of anything at all. It boots from a 1.44mB floppy disk, and enters into a BASIC interpreter, just like your favorite home computers of the 70s/80s!
Right now, not much. It boots from a 1.44mB floppy disk, and enters into a BASIC interpreter, just like your favorite home computers of the 70s/80s!
![Image of Piquant v0.1](media/screenshot.png)
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.
Currently the BASIC only understands a few simple basic commands: `PRINT`, `LIST`, `GOTO` and `RUN`. The arithmetic parser was yanked out as part of a refactor that is still ongoing so it can't do math right now. The eventual target is for this to be fully MS BASIC-80 compliant.
Beware, this is a work in progress and is probably in some state of brokenness. The last couple of git log entries should be relied upon to understand the current state.
How can I run it?
=====

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -10,20 +10,21 @@
struct basic_expr math_expressions[32];
int basic_errno;
int basic_last_stored_lineno;
int basic_run_ip = 0;
int basic_repl_mode = 0; /* 0 = REPL mode, 1 = RUN mode */
char _tokenizer_value[BASIC_TOKENIZER_MAX_LENGTH];
char *_tokenizer_prev;
char *_tokenizer_prev_next;
char basic_memory_lines[BASIC_MAX_LINES][BASIC_MAX_LINE_LENGTH];
char const_string_test[255];
void basic_report_error()
void basic_report_error(char *prefix)
{
char decimal[2];
decimal[0] = 0;
decimal[1] = 0;
_cputs("Error: ");
decimal[0] = dtoa(basic_errno);
_cputs((char *)&decimal);
_cputs(prefix);
memset(decimal, 0x00, 32);
itoa(basic_errno, decimal);
_cputs(decimal);
_cputs("\n");
}
@@ -38,40 +39,35 @@ void basic_cmd_rem(void *expr)
return;
}
void basic_cmd_goto(void *data)
{
int lineno;
if ( data == NULL ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return;
}
memset(decimal, 0x00, 32);
lineno = atoi(lstripseek(data));
basic_run_ip = lineno-1;
}
void basic_cmd_list(void *data)
{
basic_expr *expr;
char decimal[32];
int i = 0;
int x = 0;
int limit = basic_last_stored_lineno;
char *lineptr = NULL;
if ( data == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return;
}
expr = basic_parse_expr((char *)data, 0);
if ( expr == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return;
}
/* The default state of the lval integer argument is zero. Nothing special happens in the parsing
* of a "LIST" command with no integer argument that ensures this, that's just the default state.
* So the only time expr->lval.i will be non-zero is if user said "LIST NNNN". We're relying on that here.
i = 0;
/* I don't know why, but somehow, this memcpy fixes the bug where _cputs and _cputsf stops properly processing
* constant character strings passed as the format string. I've tried lots and lots of things and I still don't
* know why this fixes the bug.
*/
if ( expr->lval.i != 0 ) {
limit = expr->lval.i;
}
memset((char *)&decimal, 0x00, 32);
for ( i = 0; i < limit ; i++ ) {
if ( basic_memory_lines[i][0] != 0x00 ) {
itoa(i, (char *)&decimal);
_cputs((char *)&decimal);
/* this funky pointer dereferencing is to make bcc happy, it can't
* manage indexing the array and dereferencing that */
_cputs(((char *)&basic_memory_lines)+i);
_cputs("\n");
memcpy(const_string_test, (char *)" \0", strlen(" \0"));
for ( i = 0; i <= limit ; i++ ) {
if ( basic_memory_lines[i][0] != 0 ) {
_cputsf("%d ", (char *)(i+1));
_cputsf("%s\n", basic_memory_lines[i]);
}
}
}
@@ -85,18 +81,26 @@ void basic_cmd_print(void *data)
return;
}
expr = basic_parse_expr((char *)data, 0);
if ( expr == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return;
_cputs((char *)data);
}
memset((void *)&result, 0x00, sizeof(struct basic_variable));
basic_solve_expr(expr, &result);
if ( basic_errno != 0 ) {
void basic_cmd_run(void *data)
{
int rc = 0;
char *lineptr;
for ( basic_run_ip = 0; basic_run_ip <= basic_last_stored_lineno ; basic_run_ip++ ) {
basic_errno = 0;
if ( basic_memory_lines[basic_run_ip][0] != 0x00 ) {
rc = basic_run_line_v2((char *)basic_memory_lines[basic_run_ip], 1);
if ( rc != 0 || basic_errno != 0 ) {
_cputs("Error at Line ");
itoa(basic_run_ip+1, (char *)&decimal);
_cputs(": ");
_cputs((char *)&decimal);
_cputs("\n");
return;
} else {
basic_print_var(&result);
}
}
}
}
@@ -131,15 +135,10 @@ char *_tokenize(char *ptr, char *token)
orig = ptr;
numtokens = strlen(token);
memset(&_tokenizer_value, 0x00, BASIC_TOKENIZER_MAX_LENGTH);
memset(_tokenizer_value, 0x00, BASIC_TOKENIZER_MAX_LENGTH);
while ( *ptr != 0x0 ) {
tokenptr = token;
for ( i = 0 ; i < numtokens; i++) {
if ( *ptr == *(tokenptr + i)) {
if ( len == 0 ) {
len = 1;
ptr += 1;
}
for ( tokenptr = token ; *tokenptr != 0x00; tokenptr += 1) {
if ( *ptr == *tokenptr) {
goto _tokenize_copy;
}
}
@@ -147,21 +146,22 @@ char *_tokenize(char *ptr, char *token)
len += 1;
}
_tokenize_copy:
if ( len == 0 ) {
len = 1;
ptr += 1;
}
if ( len > BASIC_TOKENIZER_MAX_LENGTH ) {
basic_errno = BASIC_ERR_SYNTAX_TOKEN_LENGTH;
return NULL;
}
memcpy((void *)&_tokenizer_value, (void *)orig, len);
lstrip((char *)&_tokenizer_value, (char *)&tmpbuff, " ");
rstrip((char *)&tmpbuff, (char *)&_tokenizer_value, " ");
memcpy(_tokenizer_value, (void *)orig, len);
_tokenizer_prev_next = (ptr + 1);
return ptr;
}
char *tokenizer_token(void)
{
return (char *)&_tokenizer_value;
return _tokenizer_value;
}
/***************************************************************
@@ -170,216 +170,88 @@ char *tokenizer_token(void)
*
***************************************************************/
int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result)
int basic_memory_line_store(char *content, int lineno)
{
if ( expr == NULL || result == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return 0;
}
int i = 0;
char *ptr = NULL;
char *dest = NULL;
switch (expr->type) {
case BASIC_OPTP_NONE:
if ( expr->lval_type == BASIC_LVAL_CONST_INT ) {
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value.i = expr->lval.i;
} else {
basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED;
return 0;
}
break;
case BASIC_OPTP_ADD:
if ( expr->lval_type != BASIC_LVAL_CONST_INT ||
( expr->rval_type != BASIC_RVAL_CONST_INT ) ) {
if ( lineno < 0 || lineno > BASIC_MAX_LINES ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value.i = expr->lval.i + expr->rval.i;
break;
case BASIC_OPTP_SUB:
if ( expr->lval_type != BASIC_LVAL_CONST_INT ||
( expr->rval_type != BASIC_RVAL_CONST_INT ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value.i = expr->lval.i - expr->rval.i;
break;
case BASIC_OPTP_MUL:
if ( expr->lval_type != BASIC_LVAL_CONST_INT ||
( expr->rval_type != BASIC_RVAL_CONST_INT ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value.i = expr->lval.i * expr->rval.i;
break;
case BASIC_OPTP_DIV:
if ( expr->lval_type != BASIC_LVAL_CONST_INT ||
( expr->rval_type != BASIC_RVAL_CONST_INT ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return 0;
}
if ( expr->rval.i == 0) {
basic_errno = BASIC_ERR_MATH_DBZ;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
result->value.i = expr->lval.i / expr->rval.i;
break;
case BASIC_OPTP_MOD:
if ( expr->lval_type != BASIC_LVAL_CONST_INT ||
( expr->rval_type != BASIC_RVAL_CONST_INT ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return 0;
}
if ( expr->rval.i == 0) {
basic_errno = BASIC_ERR_MATH_DBZ;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
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_INT ||
( expr->rval_type != BASIC_RVAL_CONST_INT ) ) {
basic_errno = BASIC_ERR_INVALID_ARGUMENTS;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT);
if (expr->lval.i == expr->rval.i) {
result->value.i = BASIC_CONST_TRUE;
} else {
result->value.i = BASIC_CONST_FALSE;
}
break;
case BASIC_OPTP_STOR:
/* this funky pointer dereferencing is to make bcc happy, it can't
* manage indexing the array and dereferencing that */
if ( memcpy(
(((char *)&basic_memory_lines) + expr->lval.i),
(char *)expr->rval.ptr,
strlen((char *)expr->rval.ptr)
) == 0 ) {
basic_errno = BASIC_ERR_INTERNAL_MEMORY;
return 0;
}
result->flags = (result->flags | BASIC_VARFLAG_TSTR | BASIC_VARFLAG_INIT);
result->value.ptr = BASIC_MESSAGE_OK;
basic_last_stored_lineno = expr->lval.i;
return 0;
case BASIC_OPTP_ASN:
basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED;
return 0;
default:
basic_errno = BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR;
return 0;
}
return 1;
}
struct basic_expr *basic_parse_expr(char *expbuf, int require_line_numbers)
if ( lineno > basic_last_stored_lineno ) {
/*
* basic_last_stored_lineno only every grows upward (even if you go back and edit a line or insert one).
* The memory between here (new line) and there (last line) is probably uninitialized. When we come back
* through to LIST those lines later we may find garbage. Let's clean it up.
*/
for ( i = basic_last_stored_lineno+1; i <= lineno ; i++ ) {
/* We don't need to zero the entire string, just the first character, don't waste time */
basic_memory_lines[i][0] = 0x00;
}
basic_last_stored_lineno = lineno;
}
lineno -= 1;
i = (int) memcpy(basic_memory_lines[lineno], content, strlen(content));
if ( i == 0 ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return 1;
}
}
int basic_run_line_v2(char *codeline, int repl_mode)
{
struct basic_expr *ret = &math_expressions[0];
char *token = NULL;
char flags = 0;
if ( require_line_numbers == 1 ) {
flags = BASIC_PARSE_FIRSTTOKEN;
char *buffptr;
char *token;
int rc = 0;
int lineno = 0;
if ( codeline == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return 1;
}
/*char *subptr = 0;*/
_tokenizer_init();
memset(ret, 0x0, sizeof(struct basic_expr));
while ( *expbuf != '\0' ) {
if ( *expbuf == ' ' ) {
expbuf += 1;
continue;
}
expbuf = _tokenize(expbuf, " ");
/* Continue as long as there's text left in the buffer */
buffptr = lstripseek(codeline, " ");
while ( buffptr != NULL ) {
buffptr = _tokenize(buffptr, " ");
token = tokenizer_token();
if ( isdigit(*token) == 1 ) {
if ( flags == BASIC_PARSE_FIRSTTOKEN ) {
ret->type = BASIC_OPTP_STOR;
ret->lval_type = BASIC_LVAL_CONST_INT;
ret->lval.i = atoi(token);
#ifdef __GNUC__
printf("Stored line number %d for %s\n", ret->lval.i, token);
#endif
ret->rval.ptr = expbuf;
ret->rval_type = BASIC_RVAL_PTR;
break;
}
if ( (ret->type == 0) && (flags & BASIC_PARSE_FOUND_LVAL) == BASIC_PARSE_FOUND_LVAL ) {
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES;
return NULL;
} else if ( ret->type == 0x0 ) {
ret->lval.i = atoi(token);
ret->lval_type = BASIC_LVAL_CONST_INT;
flags = (flags | BASIC_PARSE_FOUND_LVAL);
} else if ( ret->type != 0x0 && ((flags & BASIC_PARSE_FOUND_RVAL) == BASIC_PARSE_FOUND_RVAL)) {
basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES;
return NULL;
} else if ( ret->type != 0x0 ) {
ret->rval.i = atoi(token);
ret->rval_type = BASIC_RVAL_CONST_INT;
}
} else if ( token != NULL && ret->type == 0x0 ) {
if ( flags == BASIC_PARSE_FIRSTTOKEN ) {
basic_errno = BASIC_ERR_SYNTAX_NO_LINE_NUMBER;
}
switch ( *token ) {
case '+':
ret->type = BASIC_OPTP_ADD;
break;
case '*':
ret->type = BASIC_OPTP_MUL;
break;
case '-':
ret->type = BASIC_OPTP_SUB;
break;
case '/':
ret->type = BASIC_OPTP_DIV;
break;
case '%':
ret->type = BASIC_OPTP_MOD;
break;
default:
/* see if a command will claim this token */
if ( strcmp(token, "REM") == 0 ) {
ret->type = BASIC_OPTP_CMD;
ret->lval_type = BASIC_LVAL_CMDPTR;
ret->lval.cmd_ptr = basic_cmd_rem;
ret->rval_type = BASIC_RVAL_NONE;
return ret;
/* is it a line number? If so, store it and do nothing else.*/
if ( isdigit(*token) ) {
memset(decimal, 0x00, 32);
lineno = atoi(token);
basic_memory_line_store(buffptr, lineno);
return 0;
/* Is it a command? */
} else if ( strcmp(token, "PRINT") == 0 ) {
ret->type = BASIC_OPTP_CMD;
ret->lval_type = BASIC_LVAL_CMDPTR;
ret->lval.cmd_ptr = basic_cmd_print;
ret->rval_type = BASIC_RVAL_PTR;
ret->rval.ptr = expbuf;
return ret;
basic_cmd_print(buffptr);
return basic_errno;
} else if ( strcmp(token, "LIST") == 0 ) {
ret->type = BASIC_OPTP_CMD;
ret->lval_type = BASIC_LVAL_CMDPTR;
ret->lval.cmd_ptr = basic_cmd_list;
ret->rval_type = BASIC_RVAL_PTR;
ret->rval.ptr = expbuf;
return ret;
basic_cmd_list(NULL);
return basic_errno;
} else if ( strcmp(token, "GOTO") == 0 ) {
basic_cmd_goto(buffptr);
return basic_errno;
} else if ( strcmp(token, "RUN") == 0 ) {
basic_repl_mode = 1;
return basic_errno;
} else {
basic_errno = BASIC_ERR_SYNTAX_GENERAL;
return NULL;
break;
basic_errno = BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR;
}
/* Report errors */
if ( basic_errno != 0 ) {
_cputsf("Parsing error: %d", basic_errno);
return 1;
}
} else {
basic_errno = BASIC_ERR_SYNTAX_GENERAL;
return NULL;
/* Move to the next thing in the line and process it */
buffptr = lstripseek(buffptr, " ");
}
}
return ret;
return 0;
}
/***************************************************************
@@ -388,9 +260,8 @@ struct basic_expr *basic_parse_expr(char *expbuf, int require_line_numbers)
*
***************************************************************/
void basic_print_var(struct basic_variable *var)
void basic_print_var(basic_variable *var)
{
char decimal[32];
memset(&decimal, 0x00, 32);
if ( ( (var->flags & BASIC_VARFLAG_INIT) == BASIC_VARFLAG_INIT ) &&
@@ -401,58 +272,44 @@ void basic_print_var(struct basic_variable *var)
_cputs("ERROR Unable to convert decimal to integer");
}
_cputs("\n");
} else if ( ( (var->flags & BASIC_VARFLAG_INIT) == BASIC_VARFLAG_INIT ) &&
( (var->flags & BASIC_VARFLAG_TSTR) == BASIC_VARFLAG_TSTR ) ) {
if ( var->value.str == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return;
} else {
_cputs(var->value.str);
}
}
}
void basic_repl(void)
{
char keybuff[512];
char outbuff[128];
struct basic_expr *expr;
int i;
char *ptr;
char *token;
blankScreen();
setCursorPosition(0, 0);
_cputs("Piquant Basic v0.1\n\n");
_cputs("Piquant Basic v0.1\n");
_cputs("READY\n");
while ( 1 ) {
expr = NULL;
_cputs("> ");
basic_errno = 0;
if ( basic_repl_mode == 1 ) {
basic_cmd_run(NULL);
basic_repl_mode = 0;
}
_cputs("\n> ");
/* Read */
memset((void *)&keybuff, 0x00, 512);
memset((void *)&outbuff, 0x00, 128);
if ( _cgets((char *)&keybuff) != NULL ) {
_cputs("\n");
/* Evaluate
* First we look for line numbers
* When we check for immediate mode operation (which catches commands like LIST)
* Then we give up
*/
expr = basic_parse_expr((char *)&keybuff, 1);
if ( basic_errno == BASIC_ERR_SYNTAX_NO_LINE_NUMBER ) {
expr = basic_parse_expr((char *)&keybuff, 0);
}
if ( expr == NULL ) {
basic_report_error();
basic_errno = 0;
continue;
}
if ( expr->lval_type == BASIC_LVAL_CMDPTR ) {
if ( expr->lval.cmd_ptr == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
basic_report_error();
basic_errno = 0;
} else {
(*expr->lval.cmd_ptr)(expr->rval.ptr);
if ( basic_errno != 0 ) {
basic_report_error();
basic_errno = 0;
}
}
}
/* Eval and Print */
basic_run_line_v2((char *)&keybuff, 1);
}
}
}

View File

@@ -2,8 +2,8 @@
#define _BASIC_H_
/* Per MS BASIC-80 ref page 1-2 */
#define BASIC_MAX_LINES sizeof(int)
#define BASIC_MAX_LINE_LENGTH 255
#define BASIC_MAX_LINES 65535
#define BASIC_MAX_LINE_LENGTH 72
#define BASIC_OPTP_NONE 0 /* No operation (only valid when LVAL is CONST and no RVAL) */
#define BASIC_OPTP_ADD 1 /* Add */
@@ -25,6 +25,8 @@
#define BASIC_RVAL_CONST_INT 5
#define BASIC_RVAL_PTR 6 /* Only used internally */
#define BASIC_RVAL_NONE 7
#define BASIC_LVAL_CONST_STR 8
#define BASIC_RVAL_CONST_STR 9
#define BASIC_PARSE_FOUND_LVAL 1
#define BASIC_PARSE_FOUND_RVAL 2
@@ -44,7 +46,7 @@
#define BASIC_MESSAGE_OK "OK\n"
#define BASIC_TOKENIZER_TOKENS "+-/%*="
#define BASIC_TOKENIZER_TOKENS " =+-*/^{}%#$!'\\,;:&?<>/@_"
#define BASIC_TOKENIZER_MAX_LENGTH 512
#define BASIC_VARNAME_MAX_LENGTH 16
@@ -86,19 +88,23 @@ typedef struct basic_variable basic_variable;
#define BASIC_CONST_FALSE 0
extern int basic_errno;
extern char basic_memory_lines[BASIC_MAX_LINES][BASIC_MAX_LINE_LENGTH];
extern int basic_last_stored_lineno;
void basic_repl(void);
basic_expr *basic_parse_expr(char *, int);
int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result);
char *tokenizer_token(void);
int basic_run_line(char *codeline, int repl_mode);
void basic_cmd_rem(void *data);
void basic_cmd_print(void *data);
void basic_cmd_list(void *data);
void basic_cmd_run(void *data);
void basic_cmd_goto(void *data);
void basic_print_var(basic_variable *var);
void basic_report_error();
void basic_report_error(char *prefix);
char *basic_memory_line_address(int lineno);
int basic_memory_line_store(char *content, int lineno);
#endif /* _BASIC_H_ */

View File

@@ -6,6 +6,8 @@
#include <stdio.h>
#endif
char decimal[32];
void _putch(char c)
{
#ifndef __GNUC__
@@ -32,13 +34,52 @@ void _cputs(char *ptr)
if ( ptr == NULL ) {
return;
}
while ((char)*ptr != 0x0) {
_putch((char)*ptr);
if (*ptr == '\n') {
_cursor_y += 1;
_cursor_x = 0;
setCursorPosition(_cursor_x, _cursor_y);
while (*ptr != 0x0) {
if (*ptr == '\\') {
ptr += 1;
switch ( *ptr ) {
case 'n':
_putch('\n');
_cursor_x = 80;
advanceCursor();
break;
}
} else {
_putch(*ptr);
if (*ptr == '\n') {
_cursor_x = 80;
}
advanceCursor();
}
ptr += 1;
}
return;
}
void _cputsf(char *ptr, char *data)
{
if ( ptr == NULL || data == NULL) {
return;
}
while (*ptr != 0) {
if ( *ptr == '%' ) {
ptr += 1;
switch ( *ptr ) {
case 'd':
memset(decimal, 0x00, 32);
itoa((int)data, decimal);
_cputs(decimal);
break;
case 's':
_cputs((char *)data);
break;
}
} else {
_putch(*ptr);
if (*ptr == '\n') {
_cursor_x = 80;
}
advanceCursor();
}
ptr += 1;

View File

@@ -4,6 +4,10 @@
void _putch(char _c);
char *_cgets(char *d);
void _cputs(char *d);
void _cputsf(char *d, char *data);
char _getkey(char *dest);
extern char decimal[32];
#endif /* _CONIO_H_ */

View File

@@ -53,9 +53,9 @@ void backupCursor()
void advanceCursor()
{
_cursor_x += 1;
if ( _cursor_x > 79 ) {
if ( _cursor_x > 72 ) {
_cursor_x = 0;
_cursor_y += 1;
if ( _cursor_y <= 23 ) _cursor_y += 1;
}
setCursorPosition(_cursor_x, _cursor_y);
}

View File

@@ -107,6 +107,28 @@ _lstrip_outer_continue:
return stripped;
}
char *lstripseek(char *s, char *strip)
{
int stripped = 0;
char *stripptr = strip;
if ( s == NULL || strip == NULL ) {
return NULL;
}
while ( *s != 0 ) {
stripped = 0;
for ( stripptr = strip; *stripptr != 0; stripptr += 1) {
if ( *s == *stripptr ) {
stripped = 1;
}
}
if ( stripped == 0 ) {
return s;
}
s += 1;
}
return NULL;
}
int rstrip(char *s1, char *s2, char *strip)
{
int stripped = 0;

View File

@@ -10,4 +10,5 @@ void *memcpy(void *dest, void *src, size_t n);
int strcmp(char *s1, char *s2);
int lstrip(char *s1, char *s2, char *strip);
int rstrip(char *s1, char *s2, char *strip);
char *lstripseek(char *s, char *strip);
#endif /* _STRING_H_ */

View File

@@ -40,7 +40,10 @@ int main(void)
if ( basic_errno != 0 ) return 8;
if ( result.flags != (BASIC_VARFLAG_INIT | BASIC_VARFLAG_TSTR) ) return 9;
if ( result.value.ptr == NULL ) return 10;
if ( strcmp((char *)&basic_memory_lines[10], expr.rval.ptr) != 0 ) return 11;
if ( basic_last_stored_lineno != 9 ) return 11;
printf("last stored line number: %d\n", basic_last_stored_lineno);
printf("stored memory line 10 equals: %s\n", basic_memory_line_address(basic_last_stored_lineno));
if ( strcmp(basic_memory_line_address(basic_last_stored_lineno), expr.rval.ptr) != 0 ) return 12;
return 0;