From 559ff15dc0e5afb3fc42e846cef88ab3cae58fac Mon Sep 17 00:00:00 2001 From: Andrew Kesterson Date: Tue, 7 May 2024 08:08:40 -0400 Subject: [PATCH] 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. --- src/basic.c | 237 +++++++++++++++++++++++++++++++++---------- src/basic.h | 10 +- tests/basic_solver.c | 5 +- 3 files changed, 192 insertions(+), 60 deletions(-) diff --git a/src/basic.c b/src/basic.c index 96b7c07..7ee6ab8 100644 --- a/src/basic.c +++ b/src/basic.c @@ -15,14 +15,13 @@ 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 decimal[32]; -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); + memset((char *)&decimal, 0x00, 32); + _cputs(prefix); + itoa(basic_errno, (char *)&decimal); _cputs((char *)&decimal); _cputs("\n"); } @@ -41,9 +40,9 @@ void basic_cmd_rem(void *expr) void basic_cmd_list(void *data) { basic_expr *expr; - char decimal[32]; int i = 0; int limit = basic_last_stored_lineno; + char *lineptr = NULL; if ( data == NULL ) { basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; @@ -62,15 +61,21 @@ void basic_cmd_list(void *data) if ( expr->lval.i != 0 ) { limit = expr->lval.i; } - + /* + _cputs("Program listing from 0 - "); memset((char *)&decimal, 0x00, 32); - for ( i = 0; i < limit ; i++ ) { - if ( basic_memory_lines[i][0] != 0x00 ) { - itoa(i, (char *)&decimal); + itoa(limit, (char *)&decimal); + _cputs((char *)&decimal); + _cputs(":\n"); + */ + for ( i = 0; i <= limit ; i++ ) { + lineptr = basic_memory_line_address(i); + if ( (char)*lineptr != 0x00 ) { + itoa(i+1, (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(lineptr); _cputs("\n"); } } @@ -81,12 +86,17 @@ void basic_cmd_print(void *data) struct basic_variable result; basic_expr *expr; if ( data == NULL ) { + _cputs("basic_cmd_print received null data\n"); basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; return; } + _cputs("basic_cmd_print parsing \""); + _cputs((char *)data); + _cputs("\"\n"); expr = basic_parse_expr((char *)data, 0); if ( expr == NULL ) { + _cputs("basic_cmd_print failed to parse the data it was given\n"); basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; return; } @@ -94,12 +104,47 @@ void basic_cmd_print(void *data) memset((void *)&result, 0x00, sizeof(struct basic_variable)); basic_solve_expr(expr, &result); if ( basic_errno != 0 ) { + _cputs("basic_cmd_print exiting on error\n"); return; } else { + _cputs("basic_cmd_print printing\n"); + _cputs("Should probably be : "); + _cputs(tokenizer_token()); + _cputs(" .. or "); + _cputs(result.value.str); + _cputs("\n"); basic_print_var(&result); } } +void basic_cmd_run(void *data) +{ + int i = 0; + int rc = 0; + char *lineptr; + for ( i = 0; i <= basic_last_stored_lineno ; i++ ) { + basic_errno = 0; + lineptr = basic_memory_line_address(i); + if ( (char)*lineptr != 0x00 ) { + _cputs("Running ["); + itoa(i+1, (char *)&decimal); + _cputs((char *)&decimal); + _cputs("] "); + _cputs(lineptr); + _cputs("\n"); + rc = basic_run_line(lineptr, 0); + if ( rc != 0 || basic_errno != 0 ) { + _cputs("Error at Line "); + itoa(i+1, (char *)&decimal); + _cputs((char *)&decimal); + _cputs(": "); + _cputs("\n"); + return; + } + } + } +} + /*************************************************************** * * Basic Tokenizer @@ -170,6 +215,11 @@ char *tokenizer_token(void) * ***************************************************************/ +char *basic_memory_line_address(int lineno) +{ + return ((char *)&basic_memory_lines) + (lineno * BASIC_MAX_LINE_LENGTH); +} + int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result) { if ( expr == NULL || result == NULL ) { @@ -179,10 +229,20 @@ int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result) switch (expr->type) { case BASIC_OPTP_NONE: + _cputs("basic_solve_expr processing constant\n"); 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 if ( expr->lval_type == BASIC_LVAL_CONST_STR ) { + _cputs("basic_solve_expr processing string: "); + result->flags = (result->flags | BASIC_VARFLAG_TSTR | BASIC_VARFLAG_INIT); + result->value.str = (char *)expr->lval.ptr; + _cputs((char *)expr->lval.ptr); + _cputs(" => "); + _cputs(result->value.str); + _cputs("\n"); } else { + _cputs("basic_solve_expr exiting early\n"); basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED; return 0; } @@ -256,18 +316,40 @@ int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result) case BASIC_OPTP_STOR: /* this funky pointer dereferencing is to make bcc happy, it can't * manage indexing the array and dereferencing that */ + #ifndef __GNUC__ + _cputs("Storing line\n"); + #endif if ( memcpy( - (((char *)&basic_memory_lines) + expr->lval.i), + basic_memory_line_address(expr->lval.i-1), (char *)expr->rval.ptr, strlen((char *)expr->rval.ptr) - ) == 0 ) { - basic_errno = BASIC_ERR_INTERNAL_MEMORY; + ) == NULL ) { + #ifndef __GNUC__ + _cputs("NULL POINTER\n"); + #endif + basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; 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; + basic_last_stored_lineno = expr->lval.i-1; + #ifdef __GNUC__ + printf("basic_memory_lines[%d] = \"%s\"\n", (expr->lval.i-1), (char *)expr->rval.ptr); + #else + memset((char *)&decimal, 0x00, 32); + _cputs("basic_memory_lines["); + itoa(expr->lval.i, (char *)&decimal); + _cputs((char *)&decimal); + _cputs(" indexed as "); + itoa(basic_last_stored_lineno, (char *)&decimal); + _cputs((char *)&decimal); + _cputs("] = \""); + _cputs(expr->rval.ptr); + _cputs("\" (Stored \""); + _cputs(basic_memory_line_address(basic_last_stored_lineno)); + _cputs("\")\n"); + #endif + break; case BASIC_OPTP_ASN: basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED; return 0; @@ -368,9 +450,26 @@ struct basic_expr *basic_parse_expr(char *expbuf, int require_line_numbers) ret->rval_type = BASIC_RVAL_PTR; ret->rval.ptr = expbuf; return ret; + } else if ( strcmp(token, "RUN") == 0 ) { + ret->type = BASIC_OPTP_CMD; + ret->lval_type = BASIC_LVAL_CMDPTR; + ret->lval.cmd_ptr = basic_cmd_run; + ret->rval_type = BASIC_RVAL_PTR; + ret->rval.ptr = expbuf; + return ret; } else { - basic_errno = BASIC_ERR_SYNTAX_GENERAL; - return NULL; + /* + * For now just treat it like a string constant and we'll improve this later + * + * basic_errno = BASIC_ERR_SYNTAX_GENERAL; + * return NULL; + */ + ret->lval_type = BASIC_LVAL_CONST_STR; + ret->lval.ptr = expbuf - strlen(token); + _cputs("basic_parse_expr string constant ret->lval.ptr = "); + _cputs((char *)ret->lval.ptr); + _cputs("\n"); + return ret; break; } } @@ -382,15 +481,60 @@ struct basic_expr *basic_parse_expr(char *expbuf, int require_line_numbers) return ret; } +int basic_run_line(char *codeline, int repl_mode) +{ + /* + * If we are running in repl mode we look for line numbers, THEN we check for immediate mode commands + * If not in repl mode we just check for immediate mode + * Then we give up + */ + basic_expr *expr = NULL; + basic_variable result; + memset(&result, 0x00, sizeof(basic_variable)); + + if ( repl_mode == 1 ) { + expr = basic_parse_expr(codeline, 1); + if ( basic_errno == BASIC_ERR_SYNTAX_NO_LINE_NUMBER ) { + basic_errno = 0; + _cputs("No line number, parsing with require_line_numbers=0\n"); + expr = basic_parse_expr(codeline, 0); + } + } else { + expr = basic_parse_expr(codeline, 0); + } + if ( expr == NULL ) { + basic_report_error("Parsing error: "); + return 1; + } + if ( expr->lval_type == BASIC_LVAL_CMDPTR ) { + if ( expr->lval.cmd_ptr == NULL ) { + basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; + basic_report_error("Solving error: "); + return 1; + } else { + (*expr->lval.cmd_ptr)(expr->rval.ptr); + if ( basic_errno != 0 ) { + basic_report_error("Command error: "); + return 1; + } + } + } else { + if ( basic_solve_expr(expr, &result) != 1 || basic_errno != 0 ) { + basic_report_error("Solving error: "); + return 1; + } + } + return 0; +} + /*************************************************************** * * Basic REPL * ***************************************************************/ -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 +545,39 @@ 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("basic_print_var has string:\n"); + _cputs(var->value.str); + } + } } void basic_repl(void) { char keybuff[512]; - char outbuff[128]; - - struct basic_expr *expr; blankScreen(); setCursorPosition(0, 0); _cputs("Piquant Basic v0.1\n\n"); while ( 1 ) { - expr = NULL; + basic_errno = 0; _cputs("> "); /* 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((char *)&keybuff, 1); } + /* The loop hangs without this here. WTF? */ + _cputs("\n"); } } diff --git a/src/basic.h b/src/basic.h index 050c8db..4714cc1 100644 --- a/src/basic.h +++ b/src/basic.h @@ -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 @@ -86,19 +88,21 @@ 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_print_var(basic_variable *var); -void basic_report_error(); - +void basic_report_error(char *prefix); +char *basic_memory_line_address(int lineno); #endif /* _BASIC_H_ */ diff --git a/tests/basic_solver.c b/tests/basic_solver.c index 106721b..2418476 100644 --- a/tests/basic_solver.c +++ b/tests/basic_solver.c @@ -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;