mirror of
https://github.com/bradgrantham/apple2a.git
synced 2025-02-17 04:30:32 +00:00
Can assign to variables.
This commit is contained in:
parent
109a0af072
commit
fd8aa963d4
134
main.c
134
main.c
@ -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;
|
||||
|
12
runtime.c
12
runtime.c
@ -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.
|
||||
*/
|
||||
|
11
runtime.h
11
runtime.h
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user