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.
This commit is contained in:
237
src/basic.c
237
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");
|
||||
}
|
||||
}
|
||||
|
||||
10
src/basic.h
10
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_ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user