Can assign to variables.

This commit is contained in:
Lawrence Kesteloot 2018-08-03 13:09:02 -07:00
parent 109a0af072
commit fd8aa963d4
3 changed files with 146 additions and 11 deletions

134
main.c
View File

@ -26,10 +26,23 @@ uint8_t title_length = 9;
#define T_POKE 0x83
#define T_RUN 0x84
#define T_NEW 0x85
#define T_PLUS 0x86
#define T_MINUS 0x87
#define T_TIMES 0x88
#define T_DIVIDE 0x89
#define T_CARET 0x8A
#define T_AND 0x8B
#define T_OR 0x8C
#define T_GREATER_THAN 0x8D
#define T_EQUALS 0x8E
#define T_LESS_THAN 0x8F
// Line number used for "no line number".
#define INVALID_LINE_NUMBER 0xFFFF
// Variable for "No more space for variables".
#define OUT_OF_VARIABLE_SPACE 0xFF
// List of tokens. The token value is the index plus 0x80.
static uint8_t *TOKEN[] = {
"HOME",
@ -38,6 +51,16 @@ static uint8_t *TOKEN[] = {
"POKE",
"RUN",
"NEW",
"+",
"-",
"*",
"/",
"^",
"AND",
"OR",
">",
"=",
"<",
};
static int16_t TOKEN_COUNT = sizeof(TOKEN)/sizeof(TOKEN[0]);
@ -225,7 +248,7 @@ static uint8_t *compile_expression(uint8_t *s) {
value = parse_uint16(&s);
compile_load_ax(value);
have_value_in_ax = 1;
} else if (*s == '+') {
} else if (*s == T_PLUS) {
plus_count += 1;
s += 1;
} else {
@ -308,6 +331,57 @@ static uint8_t *find_line(uint16_t line_number) {
return line;
}
/**
* Find a variable by name. Only the first two letters are considered.
* Advances the pointer past the variable name (including letters after
* the first two). Returns the memory address of the variable. If we
* ran out of space for variables, returns OUT_OF_VARIABLE_SPACE
* and does not modify the buffer pointer.
*/
static uint8_t find_variable(uint8_t **buffer) {
uint8_t *s = *buffer;
uint8_t *existing_name = g_variable_names;
uint8_t name[2];
int16_t var;
// Pull out the variable name.
name[0] = *s++;
if (*s != 0 && (*s & 0x80) == 0) {
name[1] = *s++;
} else {
name[1] = 0;
}
// Skip rest of name.
while (*s != 0 && (*s & 0x80) == 0) {
s++;
}
for (var = 0; var < MAX_VARIABLES; var++) {
if (existing_name[0] == 0 && existing_name[1] == 0) {
// First free entry. Allocate it.
existing_name[0] = name[0];
existing_name[1] = name[1];
break;
} else if (existing_name[0] == name[0] && existing_name[1] == name[1]) {
// Found it.
break;
}
existing_name += 2;
}
if (var == MAX_VARIABLES) {
var = OUT_OF_VARIABLE_SPACE;
} else {
// Convert index to address.
var = FIRST_VARIABLE + 2*var;
// Advance pointer.
*buffer = s;
}
return (uint8_t) var;
}
/**
* Call to configure the compilation step.
*/
@ -330,6 +404,26 @@ static void compile_buffer(uint8_t *buffer, uint16_t line_number) {
if (*s == '\0' || *s == ':') {
// Empty statement. We skip the colon below.
} else if ((*s & 0x80) == 0) {
// Not a token. Must be variable assignment.
uint8_t var = find_variable(&s);
if (var == OUT_OF_VARIABLE_SPACE) {
// TODO: Nicer error specifically for out of variable space.
error = 1;
} else {
if (*s != T_EQUALS) {
error = 1;
} else {
s += 1;
// Parse address.
s = compile_expression(s);
// Copy to var.
g_compiled[g_compiled_length++] = I_STA_ZPG;
g_compiled[g_compiled_length++] = var;
g_compiled[g_compiled_length++] = I_STX_ZPG;
g_compiled[g_compiled_length++] = var + 1;
}
}
} else if (*s == T_HOME) {
s += 1;
add_call(home);
@ -355,15 +449,17 @@ static void compile_buffer(uint8_t *buffer, uint16_t line_number) {
g_compiled[g_compiled_length++] = (uint8_t) &ptr1;
g_compiled[g_compiled_length++] = I_STX_ZPG;
g_compiled[g_compiled_length++] = (uint8_t) &ptr1 + 1;
if (*s == ',') {
if (*s != ',') {
error = 1;
} else {
s++;
// Parse value. LSB is in A.
s = compile_expression(s);
g_compiled[g_compiled_length++] = I_LDY_IMM;
g_compiled[g_compiled_length++] = 0;
g_compiled[g_compiled_length++] = I_STA_IND_Y;
g_compiled[g_compiled_length++] = (uint8_t) &ptr1;
}
// Parse value. LSB is in A.
s = compile_expression(s);
g_compiled[g_compiled_length++] = I_LDY_IMM;
g_compiled[g_compiled_length++] = 0;
g_compiled[g_compiled_length++] = I_STA_IND_Y;
g_compiled[g_compiled_length++] = (uint8_t) &ptr1;
} else {
error = 1;
}
@ -420,6 +516,14 @@ static void complete_compile_and_execute(void) {
}
}
/**
* Clear out all variables. This does not clear their value, only our
* knowledge of them.
*/
void clear_variables(void) {
memset(g_variable_names, 0, sizeof(g_variable_names));
}
/**
* Compile the stored program and execute it.
*/
@ -427,7 +531,15 @@ static void compile_stored_program(void) {
uint8_t *line = g_program;
uint8_t *next_line;
// Clear out all variables.
clear_variables();
set_up_compile();
// Generate code to zero out all variable values. Do this in the program
// itself because each RUN should clear them out.
add_call(clear_variable_values);
while ((next_line = get_next_line(line)) != 0) {
uint16_t line_number = get_line_number(line);
compile_buffer(line + 4, line_number);
@ -532,6 +644,9 @@ int16_t main(void)
// Clear stored program.
new_statement();
// Clear out all variables.
clear_variables();
// Initialize UI.
home();
@ -558,9 +673,6 @@ int16_t main(void)
// Prompt.
print("\n\n]");
// TODO crashes 6502. Delete:
// asm("ldy #1");
// asm("sta $FFFF,y");
// Keyboard input.
blink = 0;

View File

@ -16,6 +16,18 @@ uint16_t g_showing_cursor = 0;
// Character at the cursor location.
uint8_t g_cursor_ch = 0;
// List of variable names, two bytes each, in the same order they are
// in the zero page (starting at FIRST_VARIABLE). Two nuls means an unused
// slot. One-letter variable names have a nul for the second character.
uint8_t g_variable_names[MAX_VARIABLES*2];
/**
* Clear out the values of all variables.
*/
void clear_variable_values(void) {
memset((void *) FIRST_VARIABLE, 0, MAX_VARIABLES*2);
}
/**
* Return the memory location of the zero-based (x,y) position on the screen.
*/

View File

@ -3,10 +3,21 @@
#include "platform.h"
// Maximum number of variables. These fit in the zero page.
#define MAX_VARIABLES 16
// Location of first variable in zero page. See zeropage.s and zeropage.inc
// in the compiler tree. They seem to use 26 bytes, so we start after that.
// Each variable takes two bytes (int16_t).
#define FIRST_VARIABLE 26
extern uint16_t g_cursor_x;
extern uint16_t g_cursor_y;
extern uint16_t g_showing_cursor;
extern uint8_t g_cursor_ch;
extern uint8_t g_variable_names[MAX_VARIABLES*2];
void clear_variable_values(void);
uint8_t *cursor_pos(void);
void show_cursor(void);