Variable processing fixed. Labels with forward references are working.
This commit is contained in:
parent
9cd1aef2f5
commit
da0849d7fb
2 changed files with 208 additions and 118 deletions
266
src/vecparse.c
266
src/vecparse.c
|
@ -41,19 +41,21 @@ typedef struct OperatorsS {
|
||||||
typedef struct LabelS {
|
typedef struct LabelS {
|
||||||
char *key;
|
char *key;
|
||||||
int value;
|
int value;
|
||||||
|
int line;
|
||||||
} LabelT;
|
} LabelT;
|
||||||
|
|
||||||
|
|
||||||
static void ensureBufferSize(VecByteCodeT *bytecode, int needed);
|
static void ensureBufferSize(VecByteCodeT *bytecode, int needed);
|
||||||
static int labelGetValue(LabelT *labels, char *label);
|
static int labelGetValue(int lineNumber, VecByteCodeT *bytecode, LabelT *labels, LabelT ***unresolved, char *label);
|
||||||
static void outputByte(VecByteCodeT *bytecode, unsigned short word);
|
static void outputByte(VecByteCodeT *bytecode, unsigned short word);
|
||||||
static void outputWord(VecByteCodeT *bytecode, unsigned short word);
|
static void outputWord(VecByteCodeT *bytecode, unsigned short word);
|
||||||
static char *parserGetNextLine(char *str, char **savePtr);
|
static char *parserGetNextLine(char *str, char **savePtr);
|
||||||
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x);
|
static gboolean parserGetNextValue(char *token, char **valueEnd, char ***variables, int *x);
|
||||||
static int parserGetWord(char *wordList, char **tokenEnd);
|
static int parserGetWord(char *wordList, char **tokenEnd);
|
||||||
static gboolean parserGetX(char **tokenEnd, char **variables, int *x);
|
static gboolean parserGetX(char **tokenEnd, char ***variables, int *x);
|
||||||
static gboolean parserGetXY(char **tokenEnd, char **variables, int *x, int *y);
|
static gboolean parserGetXY(char **tokenEnd, char ***variables, int *x, int *y);
|
||||||
static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y, int *z);
|
static gboolean parserGetXYZ(char **tokenEnd, char ***variables, int *x, int *y, int *z);
|
||||||
|
static int variableCollect(char *value, char ***variables);
|
||||||
|
|
||||||
|
|
||||||
static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
|
static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
|
||||||
|
@ -71,13 +73,13 @@ static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int labelGetValue(LabelT *labels, char *label) {
|
static int labelGetValue(int lineNumber, VecByteCodeT *bytecode, LabelT *labels, LabelT ***unresolved, char *label) {
|
||||||
int index;
|
int index;
|
||||||
int found = -1;
|
int found = -1;
|
||||||
|
LabelT *temp;
|
||||||
|
|
||||||
// Do we know this label? We search ourselves so it's case-insensitive.
|
// Do we know this label? We search ourselves so it's case-insensitive.
|
||||||
for (index = 0; index < hmlen(labels); index++) {
|
for (index = 0; index < hmlen(labels); index++) {
|
||||||
printf("Label %d of %d; %s == %s\n", index, (int)hmlen(labels), labels[index].key, label);
|
|
||||||
if (strcasecmp(label, labels[index].key) == 0) {
|
if (strcasecmp(label, labels[index].key) == 0) {
|
||||||
found = index;
|
found = index;
|
||||||
break;
|
break;
|
||||||
|
@ -86,8 +88,12 @@ static int labelGetValue(LabelT *labels, char *label) {
|
||||||
if (found < 0) {
|
if (found < 0) {
|
||||||
// We don't yet know this label, so it's a forward reference.
|
// We don't yet know this label, so it's a forward reference.
|
||||||
// Record it with a negative location, so we can resolve it later.
|
// Record it with a negative location, so we can resolve it later.
|
||||||
index = 0 - (hmlen(labels) + 1);
|
temp = NEW(LabelT);
|
||||||
hmput(labels, label, index);
|
temp->key = strdup(label);
|
||||||
|
temp->value = bytecode->length;
|
||||||
|
temp->line = lineNumber;
|
||||||
|
arrput(*unresolved, temp);
|
||||||
|
index = 0 - ((int)arrlen(*unresolved) + 1);
|
||||||
} else {
|
} else {
|
||||||
index = labels[index].value;
|
index = labels[index].value;
|
||||||
}
|
}
|
||||||
|
@ -146,45 +152,15 @@ static char *parserGetNextLine(char *str, char **savePtr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x) {
|
static gboolean parserGetNextValue(char *token, char **valueEnd, char ***variables, int *x) {
|
||||||
char *value;
|
char *value;
|
||||||
char *endPtr = NULL;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
// Return next value in a comma separated list.
|
// Return next value in a comma separated list.
|
||||||
|
|
||||||
value = strtok_r(token, ",", valueEnd);
|
value = strtok_r(token, ",", valueEnd);
|
||||||
if (value == NULL) return FALSE;
|
if (value == NULL) return FALSE;
|
||||||
|
|
||||||
// Is it a variable or number?
|
*x = variableCollect(value, variables);
|
||||||
if (strlen(value) > 1 && value[0] == '%') {
|
|
||||||
|
|
||||||
// It's a variable. Do we know it?
|
|
||||||
*x = -1;
|
|
||||||
for (index=0; index<arrlen(variables); index++) {
|
|
||||||
if (strcasecmp(variables[index], value) == 0) {
|
|
||||||
// Set MSb to indicate it's a variable.
|
|
||||||
index |= 0x8000;
|
|
||||||
*x = index; // Found.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*x < 0) return FALSE;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// It's a number.
|
|
||||||
errno = 0; endPtr = NULL;
|
|
||||||
*x = (int)strtol(value, &endPtr, 10);
|
|
||||||
if (errno != 0 || *endPtr != 0) return FALSE;
|
|
||||||
// Is it negative? If so, we need it in our format.
|
|
||||||
if (*x < 0) {
|
|
||||||
*x = -*x;
|
|
||||||
*x |= 0x4000;
|
|
||||||
}
|
|
||||||
// Ensure MSb is cleared, so we know it's a number.
|
|
||||||
*x &= 0x7fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -214,52 +190,21 @@ static int parserGetWord(char *wordList, char **tokenEnd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetX(char **tokenEnd, char **variables, int *x) {
|
static gboolean parserGetX(char **tokenEnd, char ***variables, int *x) {
|
||||||
char *value;
|
char *value;
|
||||||
char *endPtr = NULL;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
// Return single value.
|
// Return single value.
|
||||||
|
|
||||||
value = strtok_r(NULL, " ", tokenEnd);
|
value = strtok_r(NULL, " ", tokenEnd);
|
||||||
if (value == NULL) return FALSE;
|
if (value == NULL) return FALSE;
|
||||||
|
|
||||||
// Is it a variable or number?
|
*x = variableCollect(value, variables);
|
||||||
if (strlen(value) > 1 && value[0] == '%') {
|
|
||||||
|
|
||||||
// It's a variable. Do we know it?
|
|
||||||
*x = -1;
|
|
||||||
for (index=0; index<arrlen(variables); index++) {
|
|
||||||
if (strcasecmp(variables[index], value) == 0) {
|
|
||||||
// Set MSb to indicate it's a variable.
|
|
||||||
index |= 0x8000;
|
|
||||||
*x = index; // Found.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*x < 0) return FALSE;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// It's a number.
|
|
||||||
errno = 0;
|
|
||||||
endPtr = NULL;
|
|
||||||
*x = (int)strtol(value, &endPtr, 10);
|
|
||||||
if (errno != 0 || *endPtr != 0) return FALSE;
|
|
||||||
// Is it negative? If so, we need it in our format.
|
|
||||||
if (*x < 0) {
|
|
||||||
*x = -*x;
|
|
||||||
*x |= 0x4000;
|
|
||||||
}
|
|
||||||
// Ensure MSb is cleared, so we know it's a number.
|
|
||||||
*x &= 0x7fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetXY(char **tokenEnd, char **variables, int *x, int *y) {
|
static gboolean parserGetXY(char **tokenEnd, char ***variables, int *x, int *y) {
|
||||||
char *token;
|
char *token;
|
||||||
char *valueEnd;
|
char *valueEnd;
|
||||||
|
|
||||||
|
@ -275,7 +220,7 @@ static gboolean parserGetXY(char **tokenEnd, char **variables, int *x, int *y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y, int *z) {
|
static gboolean parserGetXYZ(char **tokenEnd, char ***variables, int *x, int *y, int *z) {
|
||||||
char *token;
|
char *token;
|
||||||
char *valueEnd;
|
char *valueEnd;
|
||||||
|
|
||||||
|
@ -292,6 +237,51 @@ static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int variableCollect(char *value, char ***variables) {
|
||||||
|
int index;
|
||||||
|
int found;
|
||||||
|
char *endPtr = NULL;
|
||||||
|
char **vars = *variables;
|
||||||
|
|
||||||
|
// Is it a variable or number?
|
||||||
|
if (strlen(value) > 1 && value[0] == '%') {
|
||||||
|
|
||||||
|
// It's a variable. Do we know it?
|
||||||
|
found = -1;
|
||||||
|
for (index = 0; index < arrlen(vars); index++) {
|
||||||
|
if (strcasecmp(vars[index], value) == 0) {
|
||||||
|
found = index; // Found.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found < 0) {
|
||||||
|
// Variable is not yet known. Add it to list.
|
||||||
|
found = arrlen(vars);
|
||||||
|
arrput(vars, value);
|
||||||
|
}
|
||||||
|
// Set MSb to indicate it's a variable.
|
||||||
|
found |= 0x8000;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// It's a number.
|
||||||
|
errno = 0; endPtr = NULL;
|
||||||
|
found = (int)strtol(value, &endPtr, 10);
|
||||||
|
if (errno != 0 || *endPtr != 0) return FALSE;
|
||||||
|
// Is it negative? If so, we need it in our format.
|
||||||
|
if (found < 0) {
|
||||||
|
found = -found;
|
||||||
|
found |= 0x4000;
|
||||||
|
}
|
||||||
|
// Ensure MSb is cleared, so we know it's a number.
|
||||||
|
found &= 0x7fff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
int keyword;
|
int keyword;
|
||||||
char *line;
|
char *line;
|
||||||
|
@ -307,9 +297,11 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
int y2;
|
int y2;
|
||||||
PointT p1;
|
PointT p1;
|
||||||
PointT p2;
|
PointT p2;
|
||||||
PointT *points = NULL;
|
PointT *points = NULL; // Used to collect points for LINE
|
||||||
char **variables = NULL;
|
char **variables = NULL; // Array of known variables and their IDs
|
||||||
LabelT *labels = NULL;
|
LabelT *labels = NULL; // Known lables and their byte offsets
|
||||||
|
LabelT **unresolved = NULL; // List of unresolved label uses and their byte offsets
|
||||||
|
LabelT *label = NULL; // Temp label for creating unresolved entries
|
||||||
int result = -1; // Returns -1 on success or line number of first error.
|
int result = -1; // Returns -1 on success or line number of first error.
|
||||||
KeywordsT commands[] = {
|
KeywordsT commands[] = {
|
||||||
{ "BOX", PARSE_BOX },
|
{ "BOX", PARSE_BOX },
|
||||||
|
@ -365,6 +357,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
} else { // blank line
|
} else { // blank line
|
||||||
|
|
||||||
|
printf("[%s]\n", token);
|
||||||
|
|
||||||
// Is it math?
|
// Is it math?
|
||||||
if (strlen(token) > 1 && token[0] == '%') {
|
if (strlen(token) > 1 && token[0] == '%') {
|
||||||
|
|
||||||
|
@ -381,8 +375,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
}
|
}
|
||||||
if (y1 < 0) {
|
if (y1 < 0) {
|
||||||
// Variable is not yet known. Add it to list.
|
// Variable is not yet known. Add it to list.
|
||||||
|
y1 = arrlen(variables);
|
||||||
arrput(variables, token);
|
arrput(variables, token);
|
||||||
y1 = arrlen(variables) - 1;
|
|
||||||
}
|
}
|
||||||
// Mark as variable.
|
// Mark as variable.
|
||||||
y1 |= 0x80;
|
y1 |= 0x80;
|
||||||
|
@ -394,7 +388,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
while (math[keyword].operator) {
|
while (math[keyword].operator) {
|
||||||
if (strcasecmp(math[keyword].operator, token) == 0) {
|
if (strcasecmp(math[keyword].operator, token) == 0) {
|
||||||
// Yep! Gather arguments and generate bytecode.
|
// Yep! Gather arguments and generate bytecode.
|
||||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
if (!parserGetX(&tokenEnd, &variables, &x1)) break;
|
||||||
outputByte(bytecode, PARSE_MATH);
|
outputByte(bytecode, PARSE_MATH);
|
||||||
outputByte(bytecode, y1);
|
outputByte(bytecode, y1);
|
||||||
outputByte(bytecode, math[keyword].id);
|
outputByte(bytecode, math[keyword].id);
|
||||||
|
@ -419,7 +413,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
// Have we already used this label?
|
// Have we already used this label?
|
||||||
x2 = -1;
|
x2 = -1;
|
||||||
// We search ourselves so it's case-insensitive.
|
// We search ourselves so it's case-insensitive.
|
||||||
for (x1 = 0; x1 < hmlen(labels); x1++) {
|
for (x1 = 0; x1 < shlen(labels); x1++) {
|
||||||
if (strcasecmp(token, labels[x1].key) == 0) {
|
if (strcasecmp(token, labels[x1].key) == 0) {
|
||||||
x2 = x1;
|
x2 = x1;
|
||||||
break;
|
break;
|
||||||
|
@ -427,7 +421,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
}
|
}
|
||||||
if (x2 < 0) {
|
if (x2 < 0) {
|
||||||
// New label. Add to hashmap.
|
// New label. Add to hashmap.
|
||||||
hmput(labels, token, bytecode->length);
|
shput(labels, token, bytecode->length);
|
||||||
lineOkay = TRUE;
|
lineOkay = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,9 +441,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_BOX:
|
case PARSE_BOX:
|
||||||
// Box (value),(value) to (value),(value)
|
// Box (value),(value) to (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x1, &y1)) break;
|
||||||
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x2, &y2)) break;
|
||||||
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
|
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
||||||
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
|
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
|
||||||
|
@ -467,17 +461,17 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
case PARSE_CALL:
|
case PARSE_CALL:
|
||||||
// Call (label)
|
// Call (label)
|
||||||
if (tokenEnd == NULL) break;
|
if (tokenEnd == NULL) break;
|
||||||
x1 = labelGetValue(labels, tokenEnd);
|
|
||||||
outputByte(bytecode, PARSE_CALL);
|
outputByte(bytecode, PARSE_CALL);
|
||||||
|
x1 = labelGetValue(lineNumber, bytecode, labels, &unresolved, tokenEnd);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
lineOkay = TRUE;
|
lineOkay = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_CIRCLE:
|
case PARSE_CIRCLE:
|
||||||
// Circle (value) at (value),(value)
|
// Circle (value) at (value),(value)
|
||||||
if (!parserGetX(&tokenEnd, variables, &y2)) break;
|
if (!parserGetX(&tokenEnd, &variables, &y2)) break;
|
||||||
if (parserGetWord("AT", &tokenEnd) < 0) break;
|
if (parserGetWord("AT", &tokenEnd) < 0) break;
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x1, &y1)) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
||||||
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
|
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
|
||||||
outputByte(bytecode, PARSE_CIRCLE);
|
outputByte(bytecode, PARSE_CIRCLE);
|
||||||
|
@ -494,7 +488,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_COLOR:
|
case PARSE_COLOR:
|
||||||
// Color (short)
|
// Color (short)
|
||||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
if (!parserGetX(&tokenEnd, &variables, &x1)) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
|
||||||
outputByte(bytecode, PARSE_COLOR);
|
outputByte(bytecode, PARSE_COLOR);
|
||||||
outputByte(bytecode, x1);
|
outputByte(bytecode, x1);
|
||||||
|
@ -511,9 +505,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_ELLIPSE:
|
case PARSE_ELLIPSE:
|
||||||
// Ellipse (value),(value) to (value),(value)
|
// Ellipse (value),(value) to (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x1, &y1)) break;
|
||||||
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x2, &y2)) break;
|
||||||
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
|
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
||||||
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
|
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
|
||||||
|
@ -530,13 +524,13 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_FILL:
|
case PARSE_FILL:
|
||||||
// Fill (value),(value) {to (value}
|
// Fill (value),(value) {to (value}
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x1, &y1)) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
||||||
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
|
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
|
||||||
// Do they want to fill to a certain color? Or over the current color?
|
// Do they want to fill to a certain color? Or over the current color?
|
||||||
x2 = 16; // 16 == Fill, otherwise FillTo
|
x2 = 16; // 16 == Fill, otherwise FillTo
|
||||||
if (parserGetWord("TO", &tokenEnd) >= 0) {
|
if (parserGetWord("TO", &tokenEnd) >= 0) {
|
||||||
if (!parserGetX(&tokenEnd, variables, &x2)) break;
|
if (!parserGetX(&tokenEnd, &variables, &x2)) break;
|
||||||
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
|
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
|
||||||
}
|
}
|
||||||
outputByte(bytecode, PARSE_FILL);
|
outputByte(bytecode, PARSE_FILL);
|
||||||
|
@ -549,18 +543,18 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
case PARSE_GOTO:
|
case PARSE_GOTO:
|
||||||
// Goto (label)
|
// Goto (label)
|
||||||
if (tokenEnd == NULL) break;
|
if (tokenEnd == NULL) break;
|
||||||
x1 = labelGetValue(labels, tokenEnd);
|
|
||||||
outputByte(bytecode, PARSE_GOTO);
|
outputByte(bytecode, PARSE_GOTO);
|
||||||
|
x1 = labelGetValue(lineNumber, bytecode, labels, &unresolved, tokenEnd);
|
||||||
outputWord(bytecode, x1);
|
outputWord(bytecode, x1);
|
||||||
lineOkay = TRUE;
|
lineOkay = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_IF:
|
case PARSE_IF:
|
||||||
// If (value) (compare) (value) (goto|call) (label)
|
// If (value) (compare) (value) (goto|call) (label)
|
||||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
if (!parserGetX(&tokenEnd, &variables, &x1)) break;
|
||||||
y1 = parserGetWord("== != < > <= >=", &tokenEnd);
|
y1 = parserGetWord("== != < > <= >=", &tokenEnd);
|
||||||
if (y1 < 0) break;
|
if (y1 < 0) break;
|
||||||
if (!parserGetX(&tokenEnd, variables, &x2)) break;
|
if (!parserGetX(&tokenEnd, &variables, &x2)) break;
|
||||||
y2 = parserGetWord("goto call", &tokenEnd);
|
y2 = parserGetWord("goto call", &tokenEnd);
|
||||||
if (y2 < 0) break;
|
if (y2 < 0) break;
|
||||||
if (tokenEnd == NULL) break;
|
if (tokenEnd == NULL) break;
|
||||||
|
@ -569,7 +563,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
outputByte(bytecode, y1);
|
outputByte(bytecode, y1);
|
||||||
outputWord(bytecode, x2);
|
outputWord(bytecode, x2);
|
||||||
outputByte(bytecode, y2);
|
outputByte(bytecode, y2);
|
||||||
outputWord(bytecode, labelGetValue(labels, tokenEnd));
|
x1 = labelGetValue(lineNumber, bytecode, labels, &unresolved, tokenEnd);
|
||||||
|
outputWord(bytecode, x1);
|
||||||
|
lineOkay = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PARSE_LABEL:
|
case PARSE_LABEL:
|
||||||
|
@ -579,9 +575,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
case PARSE_LINE:
|
case PARSE_LINE:
|
||||||
// Line (value),(value) to (value),(value) [to ...]
|
// Line (value),(value) to (value),(value) [to ...]
|
||||||
points = NULL;
|
points = NULL;
|
||||||
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &p1.x, &p1.y)) break;
|
||||||
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
||||||
if (!parserGetXY(&tokenEnd, variables, &p2.x, &p2.y)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &p2.x, &p2.y)) break;
|
||||||
if (IS_NUMBER(p1.x)) if (p1.x < 0 || p1.x > 319) break;
|
if (IS_NUMBER(p1.x)) if (p1.x < 0 || p1.x > 319) break;
|
||||||
if (IS_NUMBER(p1.y)) if (p1.y < 0 || p1.y > 199) break;
|
if (IS_NUMBER(p1.y)) if (p1.y < 0 || p1.y > 199) break;
|
||||||
if (IS_NUMBER(p2.x)) if (p2.x < 0 || p2.x > 319) break;
|
if (IS_NUMBER(p2.x)) if (p2.x < 0 || p2.x > 319) break;
|
||||||
|
@ -590,7 +586,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
arrput(points, p2);
|
arrput(points, p2);
|
||||||
isOkay = TRUE;
|
isOkay = TRUE;
|
||||||
while (parserGetWord("TO", &tokenEnd) >= 0) {
|
while (parserGetWord("TO", &tokenEnd) >= 0) {
|
||||||
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) {
|
if (!parserGetXY(&tokenEnd, &variables, &p1.x, &p1.y)) {
|
||||||
// Error.
|
// Error.
|
||||||
isOkay = FALSE;
|
isOkay = FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -616,9 +612,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_PALETTE:
|
case PARSE_PALETTE:
|
||||||
// Palette (short) AS (short),(short),(short)
|
// Palette (short) AS (short),(short),(short)
|
||||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
if (!parserGetX(&tokenEnd, &variables, &x1)) break;
|
||||||
if (parserGetWord("AS", &tokenEnd) < 0) break;
|
if (parserGetWord("AS", &tokenEnd) < 0) break;
|
||||||
if (!parserGetXYZ(&tokenEnd, variables, &x2, &y1, &y2)) break;
|
if (!parserGetXYZ(&tokenEnd, &variables, &x2, &y1, &y2)) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
|
||||||
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
|
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
|
||||||
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 15) break;
|
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 15) break;
|
||||||
|
@ -633,7 +629,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_PLOT:
|
case PARSE_PLOT:
|
||||||
// Plot (value),(value)
|
// Plot (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x1, &y1)) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
||||||
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
|
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
|
||||||
outputByte(bytecode, PARSE_PLOT);
|
outputByte(bytecode, PARSE_PLOT);
|
||||||
|
@ -644,9 +640,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
|
|
||||||
case PARSE_RECTANGLE:
|
case PARSE_RECTANGLE:
|
||||||
// Rectangle (value),(value) to (value),(value)
|
// Rectangle (value),(value) to (value),(value)
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x1, &y1)) break;
|
||||||
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
if (parserGetWord("TO", &tokenEnd) < 0) break;
|
||||||
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
|
if (!parserGetXY(&tokenEnd, &variables, &x2, &y2)) break;
|
||||||
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
|
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
|
||||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
|
||||||
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
|
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
|
||||||
|
@ -710,6 +706,62 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
||||||
lineNumber++;
|
lineNumber++;
|
||||||
} // read program line
|
} // read program line
|
||||||
|
|
||||||
|
// Resolve forward label declarations and patch bytecode.
|
||||||
|
//***DEBUG***
|
||||||
|
for (y1=0; y1<shlen(labels); y1++) {
|
||||||
|
printf("Resolved - %s\n", labels[y1].key);
|
||||||
|
}
|
||||||
|
for (y1=0; y1<arrlen(unresolved); y1++) {
|
||||||
|
printf("Unresolved - %s\n", unresolved[y1]->key);
|
||||||
|
}
|
||||||
|
for (y1=0; y1<arrlen(unresolved); y1++) {
|
||||||
|
// Find offset of this unresolved label. We search ourselves so it's case-insensitive.
|
||||||
|
x2 = -1;
|
||||||
|
for (x1 = 0; x1 < shlen(labels); x1++) {
|
||||||
|
printf("Checking label %d of %d - %s == %s\n", y1, (int)arrlen(unresolved), unresolved[y1]->key, labels[x1].key);
|
||||||
|
if (strcasecmp(unresolved[y1]->key, labels[x1].key) == 0) {
|
||||||
|
x2 = x1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x2 < 0) {
|
||||||
|
// Label not found! Error!
|
||||||
|
result = unresolved[y1]->line;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Write this label offset into the unresolved offset.
|
||||||
|
bytecode->bytes[unresolved[y1]->value++] = (labels[x2].value & 0xFF00) >> 8;
|
||||||
|
bytecode->bytes[unresolved[y1]->value] = labels[x2].value & 0x00FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwind variables array if needed.
|
||||||
|
if (variables != NULL) {
|
||||||
|
while (arrlen(variables) > 0) {
|
||||||
|
token = variables[0];
|
||||||
|
//DEL(token);
|
||||||
|
arrdel(variables, 0);
|
||||||
|
}
|
||||||
|
arrfree(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwind unresolved array if needed.
|
||||||
|
if (unresolved != NULL) {
|
||||||
|
while (arrlen(unresolved) > 0) {
|
||||||
|
DEL(unresolved[0]->key);
|
||||||
|
arrdel(unresolved, 0);
|
||||||
|
}
|
||||||
|
arrfree(unresolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwind labels hashmap if needed.
|
||||||
|
if (labels != NULL) {
|
||||||
|
while (shlen(labels) > 0) {
|
||||||
|
shdel(labels, labels[0].key);
|
||||||
|
}
|
||||||
|
shfree(labels);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (value) is a 16-bit integer. Since we only need a fraction of the
|
* (value) is a 16-bit integer. Since we only need a fraction of the
|
||||||
* possible values provided by this, we steal a couple bits for our
|
* possible values provided by this, we steal a couple bits for our
|
||||||
|
|
60
src/vector.c
60
src/vector.c
|
@ -339,6 +339,9 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
jlDrawBox(self->jlc, x1, y1, x2, y2);
|
jlDrawBox(self->jlc, x1, y1, x2, y2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_CALL:
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSE_CIRCLE:
|
case PARSE_CIRCLE:
|
||||||
y2 = word(self, GET_WORD);
|
y2 = word(self, GET_WORD);
|
||||||
x1 = word(self, GET_WORD);
|
x1 = word(self, GET_WORD);
|
||||||
|
@ -384,6 +387,32 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_GOTO:
|
||||||
|
index = word(self, GET_WORD);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARSE_IF:
|
||||||
|
switch (y1) {
|
||||||
|
case 0: // ==
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // !=
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // <
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // >
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // <=
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: // >=
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSE_LABEL:
|
case PARSE_LABEL:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -521,6 +550,9 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) {
|
||||||
jlDrawColorSet(self->jlc, 15);
|
jlDrawColorSet(self->jlc, 15);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSE_RETURN:
|
||||||
|
break;
|
||||||
|
|
||||||
} // switch
|
} // switch
|
||||||
} // while
|
} // while
|
||||||
|
|
||||||
|
@ -678,17 +710,23 @@ void winVectorCreate(void) {
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
SSM(SCI_INSERTTEXT, 0, (sptr_t)
|
SSM(SCI_INSERTTEXT, 0, (sptr_t)
|
||||||
"reset\n"
|
"reset\n\n"
|
||||||
"%red = 15\n"
|
"goto red\n\n"
|
||||||
"palette %red as 15,0,0\n"
|
"yellow:\n"
|
||||||
"color %red\n"
|
"\t%yellow = %red\n"
|
||||||
"box 0,0 to 319,199\n"
|
"\t%yellow - 1\n"
|
||||||
"%yellow = %red\n"
|
"\tcolor %yellow\n"
|
||||||
"%yellow - 1\n"
|
"\tline 27,22 to 289,24 to 297,169 to 27,166 to 27,23\n"
|
||||||
"color %yellow\n"
|
"\tcolor 11\n"
|
||||||
"line 27,22 to 289,24 to 297,169 to 27,166 to 27,23\n"
|
"\tcircle 50 at 159,95\n"
|
||||||
"color 11\n"
|
"\tgoto end\n\n"
|
||||||
"circle 50 at 159,95\n"
|
"red:\n"
|
||||||
|
"\t%red = 15\n"
|
||||||
|
"\tpalette %red as 15,0,0\n"
|
||||||
|
"\tcolor %red\n"
|
||||||
|
"\tbox 0,0 to 319,199\n"
|
||||||
|
"\tgoto yellow\n\n"
|
||||||
|
"end:\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Connect editor to our code.
|
// Connect editor to our code.
|
||||||
|
|
Loading…
Add table
Reference in a new issue