WIP : Storing line numbers, detecting immediate mode vs storage mode, solver tests are not working
This commit is contained in:
109
src/basic.c
109
src/basic.c
@@ -3,13 +3,18 @@
|
||||
#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()
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
src/basic.h
23
src/basic.h
@@ -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();
|
||||
|
||||
@@ -5,6 +5,5 @@
|
||||
|
||||
void main(void)
|
||||
{
|
||||
basic_program program;
|
||||
basic_repl(&program);
|
||||
basic_repl();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user