From da0849d7fb6b06b7bf5436e2f7b558cadcbce509 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Mon, 5 Dec 2022 18:38:48 -0600 Subject: [PATCH] Variable processing fixed. Labels with forward references are working. --- src/vecparse.c | 266 +++++++++++++++++++++++++++++-------------------- src/vector.c | 60 +++++++++-- 2 files changed, 208 insertions(+), 118 deletions(-) diff --git a/src/vecparse.c b/src/vecparse.c index 4f9b6ae..503eacd 100644 --- a/src/vecparse.c +++ b/src/vecparse.c @@ -41,19 +41,21 @@ typedef struct OperatorsS { typedef struct LabelS { char *key; int value; + int line; } LabelT; 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 outputWord(VecByteCodeT *bytecode, unsigned short word); 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 gboolean parserGetX(char **tokenEnd, char **variables, int *x); -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 parserGetX(char **tokenEnd, char ***variables, int *x); +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 int variableCollect(char *value, char ***variables); 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) { - int index; - int found = -1; +static int labelGetValue(int lineNumber, VecByteCodeT *bytecode, LabelT *labels, LabelT ***unresolved, char *label) { + int index; + int found = -1; + LabelT *temp; // Do we know this label? We search ourselves so it's case-insensitive. 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) { found = index; break; @@ -86,8 +88,12 @@ static int labelGetValue(LabelT *labels, char *label) { if (found < 0) { // 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. - index = 0 - (hmlen(labels) + 1); - hmput(labels, label, index); + temp = NEW(LabelT); + temp->key = strdup(label); + temp->value = bytecode->length; + temp->line = lineNumber; + arrput(*unresolved, temp); + index = 0 - ((int)arrlen(*unresolved) + 1); } else { 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 *endPtr = NULL; - int index; // Return next value in a comma separated list. value = strtok_r(token, ",", valueEnd); if (value == NULL) return FALSE; - // Is it a variable or number? - if (strlen(value) > 1 && value[0] == '%') { - - // It's a variable. Do we know it? - *x = -1; - for (index=0; index 1 && value[0] == '%') { - - // It's a variable. Do we know it? - *x = -1; - for (index=0; index 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 keyword; char *line; @@ -307,9 +297,11 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { int y2; PointT p1; PointT p2; - PointT *points = NULL; - char **variables = NULL; - LabelT *labels = NULL; + PointT *points = NULL; // Used to collect points for LINE + char **variables = NULL; // Array of known variables and their IDs + 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. KeywordsT commands[] = { { "BOX", PARSE_BOX }, @@ -365,6 +357,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { } else { // blank line + printf("[%s]\n", token); + // Is it math? if (strlen(token) > 1 && token[0] == '%') { @@ -381,8 +375,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { } if (y1 < 0) { // Variable is not yet known. Add it to list. + y1 = arrlen(variables); arrput(variables, token); - y1 = arrlen(variables) - 1; } // Mark as variable. y1 |= 0x80; @@ -394,7 +388,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { while (math[keyword].operator) { if (strcasecmp(math[keyword].operator, token) == 0) { // Yep! Gather arguments and generate bytecode. - if (!parserGetX(&tokenEnd, variables, &x1)) break; + if (!parserGetX(&tokenEnd, &variables, &x1)) break; outputByte(bytecode, PARSE_MATH); outputByte(bytecode, y1); outputByte(bytecode, math[keyword].id); @@ -419,7 +413,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { // Have we already used this label? x2 = -1; // 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) { x2 = x1; break; @@ -427,7 +421,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { } if (x2 < 0) { // New label. Add to hashmap. - hmput(labels, token, bytecode->length); + shput(labels, token, bytecode->length); lineOkay = TRUE; } @@ -447,9 +441,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_BOX: // 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 (!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)) if (x1 < 0 || x1 > 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: // Call (label) if (tokenEnd == NULL) break; - x1 = labelGetValue(labels, tokenEnd); outputByte(bytecode, PARSE_CALL); + x1 = labelGetValue(lineNumber, bytecode, labels, &unresolved, tokenEnd); outputWord(bytecode, x1); lineOkay = TRUE; break; case PARSE_CIRCLE: // Circle (value) at (value),(value) - if (!parserGetX(&tokenEnd, variables, &y2)) break; + if (!parserGetX(&tokenEnd, &variables, &y2)) 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(y1)) if (y1 < 0 || y1 > 199) break; outputByte(bytecode, PARSE_CIRCLE); @@ -494,7 +488,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_COLOR: // Color (short) - if (!parserGetX(&tokenEnd, variables, &x1)) break; + if (!parserGetX(&tokenEnd, &variables, &x1)) break; if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break; outputByte(bytecode, PARSE_COLOR); outputByte(bytecode, x1); @@ -511,9 +505,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_ELLIPSE: // 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 (!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)) if (x1 < 0 || x1 > 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: // 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(y1)) if (y1 < 0 || y1 > 199) break; // Do they want to fill to a certain color? Or over the current color? x2 = 16; // 16 == Fill, otherwise FillTo 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; } outputByte(bytecode, PARSE_FILL); @@ -549,18 +543,18 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_GOTO: // Goto (label) if (tokenEnd == NULL) break; - x1 = labelGetValue(labels, tokenEnd); outputByte(bytecode, PARSE_GOTO); + x1 = labelGetValue(lineNumber, bytecode, labels, &unresolved, tokenEnd); outputWord(bytecode, x1); lineOkay = TRUE; break; case PARSE_IF: // If (value) (compare) (value) (goto|call) (label) - if (!parserGetX(&tokenEnd, variables, &x1)) break; + if (!parserGetX(&tokenEnd, &variables, &x1)) break; y1 = parserGetWord("== != < > <= >=", &tokenEnd); if (y1 < 0) break; - if (!parserGetX(&tokenEnd, variables, &x2)) break; + if (!parserGetX(&tokenEnd, &variables, &x2)) break; y2 = parserGetWord("goto call", &tokenEnd); if (y2 < 0) break; if (tokenEnd == NULL) break; @@ -569,7 +563,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { outputByte(bytecode, y1); outputWord(bytecode, x2); outputByte(bytecode, y2); - outputWord(bytecode, labelGetValue(labels, tokenEnd)); + x1 = labelGetValue(lineNumber, bytecode, labels, &unresolved, tokenEnd); + outputWord(bytecode, x1); + lineOkay = TRUE; break; case PARSE_LABEL: @@ -579,9 +575,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_LINE: // Line (value),(value) to (value),(value) [to ...] 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 (!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.y)) if (p1.y < 0 || p1.y > 199) 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); isOkay = TRUE; while (parserGetWord("TO", &tokenEnd) >= 0) { - if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) { + if (!parserGetXY(&tokenEnd, &variables, &p1.x, &p1.y)) { // Error. isOkay = FALSE; break; @@ -616,9 +612,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_PALETTE: // 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 (!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(x2)) if (x2 < 0 || x2 > 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: // 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(y1)) if (y1 < 0 || y1 > 199) break; outputByte(bytecode, PARSE_PLOT); @@ -644,9 +640,9 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { case PARSE_RECTANGLE: // 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 (!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)) if (x1 < 0 || x1 > 319) break; if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break; @@ -710,6 +706,62 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { lineNumber++; } // read program line + // Resolve forward label declarations and patch bytecode. + //***DEBUG*** + for (y1=0; y1key); + } + for (y1=0; y1key, 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 * possible values provided by this, we steal a couple bits for our diff --git a/src/vector.c b/src/vector.c index 0f29662..7bbe1e8 100644 --- a/src/vector.c +++ b/src/vector.c @@ -339,6 +339,9 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { jlDrawBox(self->jlc, x1, y1, x2, y2); break; + case PARSE_CALL: + break; + case PARSE_CIRCLE: y2 = word(self, GET_WORD); x1 = word(self, GET_WORD); @@ -384,6 +387,32 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { } 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: break; @@ -521,6 +550,9 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { jlDrawColorSet(self->jlc, 15); break; + case PARSE_RETURN: + break; + } // switch } // while @@ -678,17 +710,23 @@ void winVectorCreate(void) { // Debug SSM(SCI_INSERTTEXT, 0, (sptr_t) - "reset\n" - "%red = 15\n" - "palette %red as 15,0,0\n" - "color %red\n" - "box 0,0 to 319,199\n" - "%yellow = %red\n" - "%yellow - 1\n" - "color %yellow\n" - "line 27,22 to 289,24 to 297,169 to 27,166 to 27,23\n" - "color 11\n" - "circle 50 at 159,95\n" + "reset\n\n" + "goto red\n\n" + "yellow:\n" + "\t%yellow = %red\n" + "\t%yellow - 1\n" + "\tcolor %yellow\n" + "\tline 27,22 to 289,24 to 297,169 to 27,166 to 27,23\n" + "\tcolor 11\n" + "\tcircle 50 at 159,95\n" + "\tgoto end\n\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.