mirror of
https://github.com/bradgrantham/apple2a.git
synced 2024-05-31 19:41:36 +00:00
Can subtract, multiply, and divide.
This commit is contained in:
parent
5a755ca3c5
commit
e02aeeb9ec
|
@ -6,6 +6,9 @@
|
||||||
extern void pushax();
|
extern void pushax();
|
||||||
extern void popax();
|
extern void popax();
|
||||||
extern void tosaddax();
|
extern void tosaddax();
|
||||||
|
extern void tossubax();
|
||||||
|
extern void tosmulax();
|
||||||
|
extern void tosdivax();
|
||||||
|
|
||||||
// Two bytes each.
|
// Two bytes each.
|
||||||
extern unsigned int ptr1;
|
extern unsigned int ptr1;
|
||||||
|
|
16
exporter.s
16
exporter.s
|
@ -6,13 +6,21 @@
|
||||||
; See the companion header file exporter.h.
|
; See the companion header file exporter.h.
|
||||||
|
|
||||||
.import pushax
|
.import pushax
|
||||||
.import popax
|
|
||||||
.import tosaddax
|
|
||||||
.importzp ptr1
|
|
||||||
.importzp tmp1
|
|
||||||
.export _pushax := pushax
|
.export _pushax := pushax
|
||||||
|
.import popax
|
||||||
.export _popax := popax
|
.export _popax := popax
|
||||||
|
.import tosaddax
|
||||||
.export _tosaddax := tosaddax
|
.export _tosaddax := tosaddax
|
||||||
|
.import tossubax
|
||||||
|
.export _tossubax := tossubax
|
||||||
|
.import tosmulax
|
||||||
|
.export _tosmulax := tosmulax
|
||||||
|
.import tosdivax
|
||||||
|
.export _tosdivax := tosdivax
|
||||||
|
|
||||||
|
.importzp ptr1
|
||||||
.exportzp _ptr1 = ptr1
|
.exportzp _ptr1 = ptr1
|
||||||
|
|
||||||
|
.importzp tmp1
|
||||||
.exportzp _tmp1 = tmp1
|
.exportzp _tmp1 = tmp1
|
||||||
|
|
||||||
|
|
113
main.c
113
main.c
|
@ -34,8 +34,8 @@ uint8_t title_length = 9;
|
||||||
#define T_NEW 0x85
|
#define T_NEW 0x85
|
||||||
#define T_PLUS 0x86
|
#define T_PLUS 0x86
|
||||||
#define T_MINUS 0x87
|
#define T_MINUS 0x87
|
||||||
#define T_TIMES 0x88
|
#define T_ASTERISK 0x88
|
||||||
#define T_DIVIDE 0x89
|
#define T_SLASH 0x89
|
||||||
#define T_CARET 0x8A
|
#define T_CARET 0x8A
|
||||||
#define T_AND 0x8B
|
#define T_AND 0x8B
|
||||||
#define T_OR 0x8C
|
#define T_OR 0x8C
|
||||||
|
@ -46,6 +46,30 @@ uint8_t title_length = 9;
|
||||||
#define T_IF 0x91
|
#define T_IF 0x91
|
||||||
#define T_THEN 0x92
|
#define T_THEN 0x92
|
||||||
|
|
||||||
|
// Operators. These encode both the operator (high nybble) and the precedence
|
||||||
|
// (low nybble). Lower precedence has a lower low nybble value. For example,
|
||||||
|
// OP_ADD (0x99) and OP_SUB (0xA9) have the same precedence (9). By convention
|
||||||
|
// the precedence is the value of the lowest-valued operator in its class
|
||||||
|
// (OP_ADD = 0x99), but only the relative values of precedence matter. All
|
||||||
|
// of these are left-associative, as in AppleSoft BASIC. (Even though
|
||||||
|
// exponentiation really should be right-associative.)
|
||||||
|
#define OP_PRECEDENCE(op) ((op) & 0x0F)
|
||||||
|
#define OP_OR 0x00
|
||||||
|
#define OP_AND 0x11
|
||||||
|
#define OP_NOT 0x22
|
||||||
|
#define OP_LTE 0x33
|
||||||
|
#define OP_GTE 0x43
|
||||||
|
#define OP_EQ 0x55
|
||||||
|
#define OP_NEQ 0x65
|
||||||
|
#define OP_LT 0x75
|
||||||
|
#define OP_GT 0x85
|
||||||
|
#define OP_ADD 0x99
|
||||||
|
#define OP_SUB 0xA9
|
||||||
|
#define OP_MULT 0xBB
|
||||||
|
#define OP_DIV 0xCB
|
||||||
|
#define OP_NEG 0xDD
|
||||||
|
#define OP_EXP 0xEE
|
||||||
|
|
||||||
// Line number used for "no line number".
|
// Line number used for "no line number".
|
||||||
#define INVALID_LINE_NUMBER 0xFFFF
|
#define INVALID_LINE_NUMBER 0xFFFF
|
||||||
|
|
||||||
|
@ -55,6 +79,9 @@ uint8_t title_length = 9;
|
||||||
// Maximum number of lines in stored program.
|
// Maximum number of lines in stored program.
|
||||||
#define MAX_LINES 128
|
#define MAX_LINES 128
|
||||||
|
|
||||||
|
// Maximum number of operators in the operator stack.
|
||||||
|
#define MAX_OP_STACK 16
|
||||||
|
|
||||||
// Test for whether a character is a digit.
|
// Test for whether a character is a digit.
|
||||||
#define IS_DIGIT(ch) ((ch) >= '0' && (ch) <= '9')
|
#define IS_DIGIT(ch) ((ch) >= '0' && (ch) <= '9')
|
||||||
|
|
||||||
|
@ -107,6 +134,11 @@ uint8_t g_program[1024];
|
||||||
uint16_t g_line_address[MAX_LINES*2];
|
uint16_t g_line_address[MAX_LINES*2];
|
||||||
uint16_t g_line_address_count;
|
uint16_t g_line_address_count;
|
||||||
|
|
||||||
|
// Operator stack, of the expression-evaluation routines. These are from the
|
||||||
|
// OP_ constants.
|
||||||
|
uint8_t g_op_stack[MAX_OP_STACK];
|
||||||
|
uint8_t g_op_stack_size = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print the tokenized string, with tokens displayed as their full text.
|
* Print the tokenized string, with tokens displayed as their full text.
|
||||||
* Prints a newline at the end.
|
* Prints a newline at the end.
|
||||||
|
@ -321,26 +353,67 @@ static uint16_t find_line_address(uint16_t line_number) {
|
||||||
return 0xFFFF;
|
return 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop an operator off the operator stack and compile it.
|
||||||
|
*/
|
||||||
|
static void pop_operator_stack() {
|
||||||
|
uint8_t op = g_op_stack[--g_op_stack_size];
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case OP_ADD:
|
||||||
|
add_call(tosaddax);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB:
|
||||||
|
add_call(tossubax);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MULT:
|
||||||
|
add_call(tosmulax);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIV:
|
||||||
|
add_call(tosdivax);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an operator onto the operator stack. Follow the Shunting-yard
|
||||||
|
* algorithm so that higher-precedence operators are performed
|
||||||
|
* first.
|
||||||
|
*
|
||||||
|
* https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||||
|
*/
|
||||||
|
static void push_operator_stack(uint8_t op) {
|
||||||
|
// All our operators are left-associative, so no special check for the case
|
||||||
|
// of equal precedence.
|
||||||
|
while (g_op_stack_size > 0 &&
|
||||||
|
OP_PRECEDENCE(g_op_stack[g_op_stack_size - 1]) >= OP_PRECEDENCE(op)) {
|
||||||
|
|
||||||
|
pop_operator_stack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Check for g_op_stack overflow.
|
||||||
|
g_op_stack[g_op_stack_size++] = op;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an expression, generating code to compute it, leaving the
|
* Parse an expression, generating code to compute it, leaving the
|
||||||
* result in AX.
|
* result in AX.
|
||||||
*/
|
*/
|
||||||
static uint8_t *compile_expression(uint8_t *s) {
|
static uint8_t *compile_expression(uint8_t *s) {
|
||||||
int plus_count = 0;
|
|
||||||
char have_value_in_ax = 0;
|
char have_value_in_ax = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (IS_DIGIT(*s)) {
|
if (IS_DIGIT(*s)) {
|
||||||
// Parse number.
|
// Parse number.
|
||||||
uint16_t value;
|
|
||||||
|
|
||||||
if (have_value_in_ax) {
|
if (have_value_in_ax) {
|
||||||
// Push on the number stack.
|
// Push on the number stack.
|
||||||
add_call(pushax);
|
add_call(pushax);
|
||||||
}
|
}
|
||||||
|
|
||||||
value = parse_uint16(&s);
|
compile_load_ax(parse_uint16(&s));
|
||||||
compile_load_ax(value);
|
|
||||||
have_value_in_ax = 1;
|
have_value_in_ax = 1;
|
||||||
} else if (IS_FIRST_VARIABLE_LETTER(*s)) {
|
} else if (IS_FIRST_VARIABLE_LETTER(*s)) {
|
||||||
// Variable reference.
|
// Variable reference.
|
||||||
|
@ -365,16 +438,26 @@ static uint8_t *compile_expression(uint8_t *s) {
|
||||||
}
|
}
|
||||||
have_value_in_ax = 1;
|
have_value_in_ax = 1;
|
||||||
} else if (*s == T_PLUS) {
|
} else if (*s == T_PLUS) {
|
||||||
plus_count += 1;
|
|
||||||
s += 1;
|
s += 1;
|
||||||
|
push_operator_stack(OP_ADD);
|
||||||
|
} else if (*s == T_MINUS) {
|
||||||
|
s += 1;
|
||||||
|
// TODO check for unary.
|
||||||
|
push_operator_stack(OP_SUB);
|
||||||
|
} else if (*s == T_ASTERISK) {
|
||||||
|
s += 1;
|
||||||
|
push_operator_stack(OP_MULT);
|
||||||
|
} else if (*s == T_SLASH) {
|
||||||
|
s += 1;
|
||||||
|
push_operator_stack(OP_DIV);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (plus_count > 0) {
|
// Empty the operator stack.
|
||||||
add_call(tosaddax);
|
while (g_op_stack_size > 0) {
|
||||||
plus_count -= 1;
|
pop_operator_stack();
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -789,6 +872,14 @@ int16_t main(void)
|
||||||
{
|
{
|
||||||
int16_t blink;
|
int16_t blink;
|
||||||
|
|
||||||
|
// For testing generated code. TODO remove
|
||||||
|
{
|
||||||
|
int16_t a, b, c;
|
||||||
|
b = 5;
|
||||||
|
c = 6;
|
||||||
|
a = b-c;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear stored program.
|
// Clear stored program.
|
||||||
new_statement();
|
new_statement();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user