WIP : Storing line numbers, detecting immediate mode vs storage mode, solver tests are not working

This commit is contained in:
2024-05-06 17:51:42 -04:00
parent a428b905da
commit ee10cc6eb5
5 changed files with 146 additions and 53 deletions

View File

@@ -3,14 +3,19 @@
#include "conio.h"
#include "string.h"
#include "stdlib.h"
#ifdef __GNUC__
#include <stdio.h>
#endif
struct basic_expr math_expressions[32];
int basic_errno;
int basic_last_stored_lineno;
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];
void basic_report_error()
{
char decimal[2];
@@ -33,6 +38,44 @@ void basic_cmd_rem(void *expr)
return;
}
void basic_cmd_list(void *data)
{
basic_expr *expr;
char decimal[32];
int i = 0;
int limit = basic_last_stored_lineno;
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.
*/
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");
}
}
}
void basic_cmd_print(void *data)
{
struct basic_variable result;
@@ -42,11 +85,7 @@ void basic_cmd_print(void *data)
return;
}
_cputs("PRINT(");
_cputs((char *)data);
_cputs(")\n");
expr = basic_parse_expr((char *)data);
expr = basic_parse_expr((char *)data, 0);
if ( expr == NULL ) {
basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER;
return;
@@ -214,6 +253,21 @@ int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result)
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;
@@ -224,11 +278,15 @@ int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result)
return 1;
}
struct basic_expr *basic_parse_expr(char *expbuf)
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();
@@ -243,6 +301,17 @@ struct basic_expr *basic_parse_expr(char *expbuf)
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);
#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;
@@ -258,6 +327,9 @@ struct basic_expr *basic_parse_expr(char *expbuf)
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;
@@ -289,6 +361,13 @@ struct basic_expr *basic_parse_expr(char *expbuf)
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 {
basic_errno = BASIC_ERR_SYNTAX_GENERAL;
return NULL;
@@ -325,7 +404,7 @@ void basic_print_var(struct basic_variable *var)
}
}
void basic_repl(basic_program *program)
void basic_repl(void)
{
char keybuff[512];
char outbuff[128];
@@ -347,11 +426,19 @@ void basic_repl(basic_program *program)
if ( _cgets((char *)&keybuff) != NULL ) {
_cputs("\n");
/* Evaluate */
expr = basic_parse_expr((char *)&keybuff);
/* 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 ) {
@@ -360,6 +447,10 @@ void basic_repl(basic_program *program)
basic_errno = 0;
} else {
(*expr->lval.cmd_ptr)(expr->rval.ptr);
if ( basic_errno != 0 ) {
basic_report_error();
basic_errno = 0;
}
}
}
}

View File

@@ -40,24 +40,14 @@
#define BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR 8
#define BASIC_ERR_INTERNAL_UNIMPLEMENTED 9
#define BASIC_ERR_MATH_DBZ 10
#define BASIC_ERR_SYNTAX_NO_LINE_NUMBER 11
#define BASIC_MESSAGE_OK "OK\n"
#define BASIC_TOKENIZER_TOKENS "+-/%*="
#define BASIC_TOKENIZER_MAX_LENGTH 512
#define BASIC_VARNAME_MAX_LENGTH 16
struct basic_line {
int lineno;
char content[BASIC_MAX_LINE_LENGTH];
struct basic_line *nextline;
};
typedef struct basic_line basic_line;
struct basic_program {
char name[128];
basic_line *first;
};
typedef struct basic_program basic_program;
union basic_value {
char c;
int i;
@@ -97,13 +87,16 @@ typedef struct basic_variable basic_variable;
extern int basic_errno;
void basic_repl(basic_program *program);
basic_expr *basic_parse_expr(char *);
extern char basic_memory_lines[BASIC_MAX_LINES][BASIC_MAX_LINE_LENGTH];
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);
void basic_cmd_rem(void *data);
void basic_cmd_print(void *data);
void basic_cmd_list(void *data);
void basic_print_var(basic_variable *var);
void basic_report_error();

View File

@@ -5,6 +5,5 @@
void main(void)
{
basic_program program;
basic_repl(&program);
basic_repl();
}

View File

@@ -9,22 +9,8 @@ int main(void)
{
struct basic_expr *expr;
char *line;
/*struct basic_line *retline;
struct basic_line *arrayline;*/
/* Store a line */
/* expr = basic_parse_expr("10 =1 + 1");
if ( expr == NULL ) return 1;
if ( expr->lval_type != BASIC_LVAL_CONST_INT ) return 2;
if ( expr->rval_type != BASIC_RVAL_PTR ) return 3;
if ( expr->lval.i != 10 ) return 4;
if ( expr->rval.ptr == NULL ) return 5;
if ( expr->type != BASIC_OPTP_STOR ) return 6;
*/
/* Parse the stored line */
/* retline = (basic_line *)expr->rval.ptr;
expr = basic_parse_expr(retline->content);*/
expr = basic_parse_expr("1 + 1");
expr = basic_parse_expr("1 + 1", 0);
if ( expr == NULL ) return 7;
if ( expr->lval_type != BASIC_LVAL_CONST_INT ) return 8;
if ( expr->rval_type != BASIC_RVAL_CONST_INT ) return 9;
@@ -33,7 +19,7 @@ int main(void)
if ( expr->type != BASIC_OPTP_ADD ) return 12;
line = "REM This is a comment that gets ignored";
expr = basic_parse_expr(line);
expr = basic_parse_expr(line, 1);
printf("%s\n", line);
printf("token = %s\n", tokenizer_token());
printf("errno = %d\n", basic_errno);
@@ -43,7 +29,7 @@ int main(void)
if ( expr->lval.cmd_ptr != &basic_cmd_rem ) return 16;
line = "PRINT 10";
expr = basic_parse_expr(line);
expr = basic_parse_expr(line, 1);
printf("%s\n", line);
printf("token = %s\n", tokenizer_token());
printf("errno = %d\n", basic_errno);
@@ -57,7 +43,7 @@ int main(void)
if ( strcmp((char *)expr->rval.ptr, " 10") != 0 ) return 23;
line = " 10"; /* ... continuing logic from the previous */
expr = basic_parse_expr(line);
expr = basic_parse_expr(line, 0);
printf("%s\n", line);
printf("token = %s\n", tokenizer_token());
printf("errno = %d\n", basic_errno);
@@ -68,14 +54,25 @@ int main(void)
if ( expr->lval_type != BASIC_LVAL_CONST_INT ) return 26;
if ( expr->lval.i != 10 ) return 27;
/* Store a line */
expr = basic_parse_expr("10 REM ignore me", 1);
if ( expr == NULL ) return 28;
if ( expr->lval_type != BASIC_LVAL_CONST_INT ) return 29;
if ( expr->rval_type != BASIC_RVAL_PTR ) return 30;
if ( expr->lval.i != 10 ) return 31;
if ( expr->rval.ptr == NULL ) return 32;
if ( strcmp(expr->rval.ptr, " REM ignore me") != 0 ) return 33;
if ( expr->type != BASIC_OPTP_STOR ) return 34;
/* Immediate mode commands should set basic_errno when line numbers are requested */
line = "PRINT 10";
expr = basic_parse_expr(line, 1);
printf("%s\n", line);
printf("token = %s\n", tokenizer_token());
printf("errno = %d\n", basic_errno);
printf("rval.ptr = '%s'\n", (char *)expr->rval.ptr);
if ( expr == NULL ) return 34;
if ( basic_errno != BASIC_ERR_SYNTAX_NO_LINE_NUMBER ) return 36;
/*
arrayline = &basic_memory_lines[0];
if ( retline != arrayline) return 13;
printf("Line 10 in memory is %d : %s (%p)\n", arrayline->lineno, (char *)&arrayline->content, (void *)arrayline->nextline);
if ( arrayline->lineno != 10 ) return 14;
if ( strcmp((char *)&arrayline->content, "=1 + 1") != 0) return 15;
if ( arrayline->nextline != NULL ) return 16;
*/
return 0;
}

View File

@@ -30,6 +30,19 @@ int main(void)
if ( result.flags != (BASIC_VARFLAG_INIT | BASIC_VARFLAG_TINT) ) return 6;
if ( result.value.i != 1 ) return 7;
expr.type = BASIC_OPTP_STOR;
expr.lval_type = BASIC_LVAL_CONST_INT;
expr.rval_type = BASIC_RVAL_PTR;
expr.lval.i = 10;
expr.rval.ptr = " REM ignore me";
memset(&result, 0x00, sizeof(basic_variable));
basic_solve_expr(&expr, &result);
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;
return 0;