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.
This commit is contained in:
303
src/basic.c
303
src/basic.c
@@ -17,6 +17,7 @@ char *_tokenizer_prev;
|
|||||||
char *_tokenizer_prev_next;
|
char *_tokenizer_prev_next;
|
||||||
char basic_memory_lines[BASIC_MAX_LINES][BASIC_MAX_LINE_LENGTH];
|
char basic_memory_lines[BASIC_MAX_LINES][BASIC_MAX_LINE_LENGTH];
|
||||||
char decimal[32];
|
char decimal[32];
|
||||||
|
char const_string_test[255];
|
||||||
|
|
||||||
void basic_report_error(char *prefix)
|
void basic_report_error(char *prefix)
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,12 @@ void basic_cmd_list(void *data)
|
|||||||
char *lineptr = NULL;
|
char *lineptr = NULL;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
_cputs("OMG WTF BBQ\n");
|
/* I don't know why, but somehow, this makes the interspersed _cputs() calls below work.
|
||||||
|
* Take this out, and those lines stop working.
|
||||||
|
* WHAT. THE. FUCK.
|
||||||
|
*/
|
||||||
|
memcpy((char *)&const_string_test, (char *)"OMG WTF BBQ\n\0", strlen("OMG WTF BBQ\n\0"));
|
||||||
|
_cputs((char *)&const_string_test);
|
||||||
for ( i = 0; i <= limit ; i++ ) {
|
for ( i = 0; i <= limit ; i++ ) {
|
||||||
lineptr = basic_memory_line_address(i);
|
lineptr = basic_memory_line_address(i);
|
||||||
if ( lineptr == NULL ) {
|
if ( lineptr == NULL ) {
|
||||||
@@ -70,19 +76,7 @@ void basic_cmd_print(void *data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr = basic_parse_expr((char *)data, 0);
|
_cputs((char *)data);
|
||||||
if ( expr == NULL ) {
|
|
||||||
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset((void *)&result, 0x00, sizeof(struct basic_variable));
|
|
||||||
basic_solve_expr(expr, &result);
|
|
||||||
if ( basic_errno != 0 ) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
basic_print_var(&result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void basic_cmd_run(void *data)
|
void basic_cmd_run(void *data)
|
||||||
@@ -192,11 +186,14 @@ int basic_memory_line_store(char *content, int lineno)
|
|||||||
|
|
||||||
dest = basic_memory_line_address(lineno);
|
dest = basic_memory_line_address(lineno);
|
||||||
if ( lineno > basic_last_stored_lineno ) {
|
if ( lineno > basic_last_stored_lineno ) {
|
||||||
/* The memory between here and there is probably uninitialized. When we come back
|
/*
|
||||||
|
* 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.
|
* 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++ ) {
|
for ( i = basic_last_stored_lineno+1; i <= lineno ; i++ ) {
|
||||||
ptr = basic_memory_line_address(i);
|
ptr = basic_memory_line_address(i);
|
||||||
|
/* We don't need to zero the entire string, just the first character, don't waste time */
|
||||||
memset(ptr, 0x00, BASIC_MAX_LINE_LENGTH);
|
memset(ptr, 0x00, BASIC_MAX_LINE_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,232 +206,6 @@ int basic_memory_line_store(char *content, int lineno)
|
|||||||
basic_last_stored_lineno = lineno;
|
basic_last_stored_lineno = lineno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result)
|
|
||||||
{
|
|
||||||
if ( expr == NULL || result == NULL ) {
|
|
||||||
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 if ( expr->lval_type == BASIC_LVAL_CONST_STR ) {
|
|
||||||
result->flags = (result->flags | BASIC_VARFLAG_TSTR | BASIC_VARFLAG_INIT);
|
|
||||||
result->value.str = (char *)expr->lval.ptr;
|
|
||||||
} 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 ) ) {
|
|
||||||
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(
|
|
||||||
basic_memory_line_address(expr->lval.i-1),
|
|
||||||
(char *)expr->rval.ptr,
|
|
||||||
strlen((char *)expr->rval.ptr)
|
|
||||||
) == NULL ) {
|
|
||||||
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-1;
|
|
||||||
break;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
struct basic_expr *ret = &math_expressions[0];
|
|
||||||
char *token = NULL;
|
|
||||||
char flags = 0;
|
|
||||||
if ( require_line_numbers == 1 ) {
|
|
||||||
flags = BASIC_PARSE_FIRSTTOKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*char *subptr = 0;*/
|
|
||||||
|
|
||||||
_tokenizer_init();
|
|
||||||
memset(ret, 0x0, sizeof(struct basic_expr));
|
|
||||||
|
|
||||||
while ( *expbuf != '\0' ) {
|
|
||||||
if ( *expbuf == ' ' ) {
|
|
||||||
expbuf += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
expbuf = _tokenize(expbuf, " ");
|
|
||||||
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);
|
|
||||||
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;
|
|
||||||
} 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;
|
|
||||||
} 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;
|
|
||||||
} 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 {
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
return ret;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
basic_errno = BASIC_ERR_SYNTAX_GENERAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int basic_run_line_v2(char *codeline, int repl_mode)
|
int basic_run_line_v2(char *codeline, int repl_mode)
|
||||||
{
|
{
|
||||||
char *buffptr;
|
char *buffptr;
|
||||||
@@ -484,52 +255,6 @@ int basic_run_line_v2(char *codeline, int repl_mode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
* Basic REPL
|
||||||
@@ -571,10 +296,10 @@ void basic_repl(void)
|
|||||||
_cputs("READY\n");
|
_cputs("READY\n");
|
||||||
|
|
||||||
basic_repl_mode = 1;
|
basic_repl_mode = 1;
|
||||||
/*basic_memory_line_store("LIST", 10);
|
basic_memory_line_store("LIST", 10);
|
||||||
basic_memory_line_store("PRINT HELLO\n", 20);
|
basic_memory_line_store("PRINT HELLO\n", 20);
|
||||||
basic_memory_line_store("PRINT WORLD\n", 30);
|
basic_memory_line_store("PRINT WORLD\n", 30);
|
||||||
basic_memory_line_store("PRINT GOODBYE\n", 40);*/
|
basic_memory_line_store("PRINT GOODBYE\n", 40);
|
||||||
|
|
||||||
while ( 1 ) {
|
while ( 1 ) {
|
||||||
basic_errno = 0;
|
basic_errno = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user