Leading whitespace is now ignored and blank lines will not throw off where the error mark is displayed. Start of labels.

This commit is contained in:
Scott Duensing 2022-12-04 19:56:56 -06:00
parent 4c644e0eaa
commit 5c5fdf3375

View file

@ -21,6 +21,7 @@
#include <errno.h> #include <errno.h>
#include <ctype.h>
#include "common.h" #include "common.h"
#include "vecparse.h" #include "vecparse.h"
@ -38,15 +39,21 @@ typedef struct OperatorsS {
ParserMathT id; ParserMathT id;
} OperatorsT; } OperatorsT;
typedef struct LabelS {
char *key;
int value;
} LabelT;
static void ensureBufferSize(VecByteCodeT *bytecode, int needed);
static void outputByte(VecByteCodeT *bytecode, unsigned short word); static void ensureBufferSize(VecByteCodeT *bytecode, int needed);
static void outputWord(VecByteCodeT *bytecode, unsigned short word); static void outputByte(VecByteCodeT *bytecode, unsigned short word);
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x); static void outputWord(VecByteCodeT *bytecode, unsigned short word);
static gboolean parserGetWord(char *word, char **tokenEnd); static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x);
static gboolean parserGetX(char **tokenEnd, char **variables, int *x); static gboolean parserGetWord(char *word, char **tokenEnd);
static gboolean parserGetXY(char **tokenEnd, char **variables, int *x, int *y); static gboolean parserGetX(char **tokenEnd, char **variables, int *x);
static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y, int *z); 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 char *strtoke(char *str, const char *delim, char **savePtr);
static void ensureBufferSize(VecByteCodeT *bytecode, int needed) { static void ensureBufferSize(VecByteCodeT *bytecode, int needed) {
@ -101,7 +108,6 @@ static gboolean parserGetNextValue(char *token, char **valueEnd, char **variable
// It's a variable. Do we know it? // It's a variable. Do we know it?
*x = -1; *x = -1;
for (index=0; index<arrlen(variables); index++) { for (index=0; index<arrlen(variables); index++) {
printf("Checking GN %d of %ld, %s = %s\n", index, arrlen(variables), variables[index], value);
if (strcasecmp(variables[index], value) == 0) { if (strcasecmp(variables[index], value) == 0) {
// Set MSb to indicate it's a variable. // Set MSb to indicate it's a variable.
index |= 0x8000; index |= 0x8000;
@ -159,7 +165,6 @@ static gboolean parserGetX(char **tokenEnd, char **variables, int *x) {
// It's a variable. Do we know it? // It's a variable. Do we know it?
*x = -1; *x = -1;
for (index=0; index<arrlen(variables); index++) { for (index=0; index<arrlen(variables); index++) {
printf("Checking GX %d of %ld, %s = %s\n", index, arrlen(variables), variables[index], value);
if (strcasecmp(variables[index], value) == 0) { if (strcasecmp(variables[index], value) == 0) {
// Set MSb to indicate it's a variable. // Set MSb to indicate it's a variable.
index |= 0x8000; index |= 0x8000;
@ -222,6 +227,59 @@ static gboolean parserGetXYZ(char **tokenEnd, char **variables, int *x, int *y,
} }
// Custom strtok_r because:
// A sequence of two or more contiguous delimiter bytes in the
// parsed string is considered to be a single delimiter.
// Which is exactly what we don't want for the line parser.
static char *strtoke(char *str, const char *delim, char **savePtr) {
/*
char *end = NULL;
if (str == NULL) {
str = *savePtr;
}
if (*str == 0) {
*savePtr = str;
return NULL;
}
str = strpbrk(str, delim);
end = str + 1;
if (*end == 0) {
*savePtr++ = end;
return str;
}
*end = 0;
*savePtr = end + 1;
return str;
*/
char *token = NULL; // found token
// assign new start in case
if (str) {
*savePtr = str;
}
// check whether text to parse left
if (!*savePtr) {
return NULL;
}
// remember current start as found token
token = *savePtr;
// find next occurrence of delim
*savePtr = strpbrk(*savePtr, delim);
// replace delim with terminator and move start to follower
if (*savePtr) {
**savePtr = 0;
*savePtr = *savePtr + 1;
}
// done
return token;
}
int vecparser(char *programIn, VecByteCodeT *bytecode) { int vecparser(char *programIn, VecByteCodeT *bytecode) {
int keyword; int keyword;
char *line; char *line;
@ -239,6 +297,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
PointT p2; PointT p2;
PointT *points = NULL; PointT *points = NULL;
char **variables = NULL; char **variables = NULL;
LabelT *labels = NULL;
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 },
@ -273,291 +332,312 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
// Parse code. // Parse code.
lineNumber = 0; lineNumber = 0;
line = strtok_r(programIn, "\n", &lineEnd); line = strtoke(programIn, "\n", &lineEnd);
while (line != NULL && (line[0] == ' ' || line[0] == '\t')) line++;
while (line != NULL) { while (line != NULL) {
printf("%d [%s]\n", lineNumber, line);
// Get the first token on the line. // Get the first token on the line.
token = strtok_r(line, " ", &tokenEnd); token = strtok_r(line, " ", &tokenEnd);
// Is this something we care about? It'll be math, a label, or a keyword. // Is this something we care about? It'll be math, a label, or a keyword.
lineOkay = FALSE; lineOkay = FALSE;
// Is it math? // Is this a blank line?
if (strlen(token) > 1 && token[0] == '%') { if (token == NULL) {
// We're doing some kind of math. // Yep - just move on.
lineOkay = TRUE;
// Look up variable index in table, or add it if needed. } else { // blank line
// Variable index is stored in y1 for later.
y1 = -1;
for (y2=0; y2<arrlen(variables); y2++) {
if (strcasecmp(variables[y2], token) == 0) {
y1 = y2; // Found.
break;
}
}
if (y1 < 0) {
// Variable is not yet known. Add it to list.
arrput(variables, token);
y1 = arrlen(variables) - 1;
}
// Mark as variable.
y1 |= 0x80;
// Find the operator. // Is it math?
token = strtok_r(NULL, " ", &tokenEnd); if (strlen(token) > 1 && token[0] == '%') {
if (token != NULL) {
keyword = 0; // We're doing some kind of math.
while (math[keyword].operator) {
if (strcasecmp(math[keyword].operator, token) == 0) { // Look up variable index in table, or add it if needed.
// Yep! Gather arguments and generate bytecode. // Variable index is stored in y1 for later.
if (!parserGetX(&tokenEnd, variables, &x1)) break; y1 = -1;
outputByte(bytecode, PARSE_MATH); for (y2 = 0; y2 < arrlen(variables); y2++) {
outputByte(bytecode, y1); if (strcasecmp(variables[y2], token) == 0) {
outputByte(bytecode, math[keyword].id); y1 = y2; // Found.
outputWord(bytecode, x1);
lineOkay = TRUE;
//***DEBUG***
if (math[keyword].id == MATH_ASSIGN) {
for (y1=0; y1<arrlen(variables); y1++) {
printf("Variable %d = %s\n", y1, variables[y1]);
}
}
break; break;
} }
keyword++;
} }
} if (y1 < 0) {
// Variable is not yet known. Add it to list.
arrput(variables, token);
y1 = arrlen(variables) - 1;
}
// Mark as variable.
y1 |= 0x80;
} else { // doing math // Find the operator.
token = strtok_r(NULL, " ", &tokenEnd);
if (token != NULL) {
keyword = 0;
while (math[keyword].operator) {
if (strcasecmp(math[keyword].operator, token) == 0) {
// Yep! Gather arguments and generate bytecode.
if (!parserGetX(&tokenEnd, variables, &x1)) break;
outputByte(bytecode, PARSE_MATH);
outputByte(bytecode, y1);
outputByte(bytecode, math[keyword].id);
outputWord(bytecode, x1);
lineOkay = TRUE;
break;
}
keyword++;
}
}
// Is it a label? } else { // doing math
if (strlen(token) > 1 && token[strlen(token) - 1] == ':') {
// It's a label. // Is it a label?
if (strlen(token) > 1 && token[strlen(token) - 1] == ':') {
} else { // doing a label // It's a label.
// It's a keyword. // Have we already used this label?
keyword = 0; x2 = -1;
while (commands[keyword].command) { for (x1 = 0; x1 < hmlen(labels); x1++) {
if (strcasecmp(commands[keyword].command, token) == 0) { if (strcasecmp(token, labels[x1].key) == 0) {
x2 = x1;
break;
}
}
if (x2 < 0) {
// New label. Add to hashmap.
hmput(labels, token, bytecode->length);
lineOkay = TRUE;
}
// Yep! Gather arguments and generate bytecode. } else { // doing a label
switch (commands[keyword].id) {
case PARSE_NONE: // It's a keyword.
// Won't happen, but silences an error. keyword = 0;
break; while (commands[keyword].command) {
if (strcasecmp(commands[keyword].command, token) == 0) {
case PARSE_BOX: // Yep! Gather arguments and generate bytecode.
// Box (value),(value) to (value),(value) switch (commands[keyword].id) {
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
if (!parserGetWord("TO", &tokenEnd)) 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;
if (IS_NUMBER(y1) && IS_NUMBER(y2)) if (y2 < y1) break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 199) break;
outputByte(bytecode, PARSE_BOX);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
outputWord(bytecode, x2);
outputWord(bytecode, y2);
lineOkay = TRUE;
break;
case PARSE_CIRCLE: case PARSE_NONE:
// Circle (value) at (value),(value) // Won't happen, but silences an error.
if (!parserGetX(&tokenEnd, variables, &y2)) break; break;
if (!parserGetWord("AT", &tokenEnd)) 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);
outputWord(bytecode, y2);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
lineOkay = TRUE;
break;
case PARSE_CLEAR: case PARSE_BOX:
outputByte(bytecode, PARSE_CLEAR); // Box (value),(value) to (value),(value)
lineOkay = TRUE; if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
break; if (!parserGetWord("TO", &tokenEnd)) 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;
if (IS_NUMBER(y1) && IS_NUMBER(y2)) if (y2 < y1) break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 199) break;
outputByte(bytecode, PARSE_BOX);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
outputWord(bytecode, x2);
outputWord(bytecode, y2);
lineOkay = TRUE;
break;
case PARSE_COLOR: case PARSE_CIRCLE:
// Color (short) // Circle (value) at (value),(value)
if (!parserGetX(&tokenEnd, variables, &x1)) break; if (!parserGetX(&tokenEnd, variables, &y2)) break;
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break; if (!parserGetWord("AT", &tokenEnd)) break;
outputByte(bytecode, PARSE_COLOR); if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
outputByte(bytecode, x1); if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
lineOkay = TRUE; if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
break; outputByte(bytecode, PARSE_CIRCLE);
outputWord(bytecode, y2);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
lineOkay = TRUE;
break;
case PARSE_COMMENT: case PARSE_CLEAR:
// Eat the rest of the line. outputByte(bytecode, PARSE_CLEAR);
while (token != NULL) { lineOkay = TRUE;
token = strtok_r(NULL, " ", &tokenEnd); break;
}
lineOkay = TRUE;
break;
case PARSE_ELLIPSE: case PARSE_COLOR:
// Ellipse (value),(value) to (value),(value) // Color (short)
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break; if (!parserGetX(&tokenEnd, variables, &x1)) break;
if (!parserGetWord("TO", &tokenEnd)) break; if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break; outputByte(bytecode, PARSE_COLOR);
if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break; outputByte(bytecode, x1);
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break; lineOkay = TRUE;
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break; break;
if (IS_NUMBER(y1) && IS_NUMBER(y2)) if (y2 < y1) break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 199) break;
outputByte(bytecode, PARSE_ELLIPSE);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
outputWord(bytecode, x2);
outputWord(bytecode, y2);
lineOkay = TRUE;
break;
case PARSE_FILL: case PARSE_COMMENT:
// Fill (value),(value) {to (value} // Eat the rest of the line.
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break; while (token != NULL) {
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break; token = strtok_r(NULL, " ", &tokenEnd);
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break; }
// Do they want to fill to a certain color? Or over the current color? lineOkay = TRUE;
x2 = 16; // 16 == Fill, otherwise FillTo break;
if (parserGetWord("TO", &tokenEnd)) {
if (!parserGetX(&tokenEnd, variables, &x2)) break;
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
}
outputByte(bytecode, PARSE_FILL);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
outputByte(bytecode, x2);
lineOkay = TRUE;
break;
case PARSE_LABEL: case PARSE_ELLIPSE:
// Won't happen. // Ellipse (value),(value) to (value),(value)
break; if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
if (!parserGetWord("TO", &tokenEnd)) 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;
if (IS_NUMBER(y1) && IS_NUMBER(y2)) if (y2 < y1) break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 199) break;
outputByte(bytecode, PARSE_ELLIPSE);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
outputWord(bytecode, x2);
outputWord(bytecode, y2);
lineOkay = TRUE;
break;
case PARSE_LINE: case PARSE_FILL:
// Line (value),(value) to (value),(value) [to ...] // Fill (value),(value) {to (value}
points = NULL; if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) break; if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
if (!parserGetWord("TO", &tokenEnd)) break; if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
if (!parserGetXY(&tokenEnd, variables, &p2.x, &p2.y)) break; // Do they want to fill to a certain color? Or over the current color?
if (IS_NUMBER(p1.x)) if (p1.x < 0 || p1.x > 319) break; x2 = 16; // 16 == Fill, otherwise FillTo
if (IS_NUMBER(p1.y)) if (p1.y < 0 || p1.y > 199) break; if (parserGetWord("TO", &tokenEnd)) {
if (IS_NUMBER(p2.x)) if (p2.x < 0 || p2.x > 319) break; if (!parserGetX(&tokenEnd, variables, &x2)) break;
if (IS_NUMBER(p2.y)) if (p2.y < 0 || p2.y > 199) break; if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
arrput(points, p1); }
arrput(points, p2); outputByte(bytecode, PARSE_FILL);
isOkay = TRUE; outputWord(bytecode, x1);
while (parserGetWord("TO", &tokenEnd)) { outputWord(bytecode, y1);
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) { outputByte(bytecode, x2);
// Error. Unwind array. lineOkay = TRUE;
break;
case PARSE_LABEL:
// Won't happen.
break;
case PARSE_LINE:
// Line (value),(value) to (value),(value) [to ...]
points = NULL;
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) break;
if (!parserGetWord("TO", &tokenEnd)) 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;
if (IS_NUMBER(p2.y)) if (p2.y < 0 || p2.y > 199) break;
arrput(points, p1);
arrput(points, p2);
isOkay = TRUE;
while (parserGetWord("TO", &tokenEnd)) {
if (!parserGetXY(&tokenEnd, variables, &p1.x, &p1.y)) {
// Error. Unwind array.
while (arrlen(points) > 0) {
arrdel(points, 0);
}
arrfree(points);
isOkay = FALSE;
break;
}
arrput(points, p1);
}
if (isOkay) {
outputByte(bytecode, PARSE_LINE);
outputWord(bytecode, arrlen(points));
for (x1 = 0; x1 < arrlen(points); x1++) {
outputWord(bytecode, points[x1].x);
outputWord(bytecode, points[x1].y);
}
// Unwind array.
while (arrlen(points) > 0) { while (arrlen(points) > 0) {
arrdel(points, 0); arrdel(points, 0);
} }
arrfree(points); arrfree(points);
isOkay = FALSE; lineOkay = TRUE;
break;
} }
arrput(points, p1); break;
}
if (isOkay) { case PARSE_MATH:
outputByte(bytecode, PARSE_LINE); // Won't happen.
outputWord(bytecode, arrlen(points)); break;
for (x1 = 0; x1 < arrlen(points); x1++) {
outputWord(bytecode, points[x1].x); case PARSE_PALETTE:
outputWord(bytecode, points[x1].y); // Palette (short) AS (short),(short),(short)
} if (!parserGetX(&tokenEnd, variables, &x1)) break;
// Unwind array. if (!parserGetWord("AS", &tokenEnd)) break;
while (arrlen(points) > 0) { if (!parserGetXYZ(&tokenEnd, variables, &x2, &y1, &y2)) break;
arrdel(points, 0); if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
} if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break;
arrfree(points); if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 15) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 15) break;
outputByte(bytecode, PARSE_PALETTE);
outputByte(bytecode, x1);
outputByte(bytecode, x2);
outputByte(bytecode, y1);
outputByte(bytecode, y2);
lineOkay = TRUE; lineOkay = TRUE;
} break;
break;
case PARSE_MATH: case PARSE_PLOT:
// Won't happen. // Plot (value),(value)
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);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
lineOkay = TRUE;
break;
case PARSE_PALETTE: case PARSE_RECTANGLE:
// Palette (short) AS (short),(short),(short) // Rectangle (value),(value) to (value),(value)
if (!parserGetX(&tokenEnd, variables, &x1)) break; if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
if (!parserGetWord("AS", &tokenEnd)) break; if (!parserGetWord("TO", &tokenEnd)) break;
if (!parserGetXYZ(&tokenEnd, variables, &x2, &y1, &y2)) break; if (!parserGetXY(&tokenEnd, variables, &x2, &y2)) break;
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break; if (IS_NUMBER(x1) && IS_NUMBER(x2)) if (x2 < x1) break;
if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 15) break; if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 15) break; if (IS_NUMBER(x2)) if (x2 < 0 || x2 > 319) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 15) break; if (IS_NUMBER(y1) && IS_NUMBER(y2)) if (y2 < y1) break;
outputByte(bytecode, PARSE_PALETTE); if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
outputByte(bytecode, x1); if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 199) break;
outputByte(bytecode, x2); outputByte(bytecode, PARSE_RECTANGLE);
outputByte(bytecode, y1); outputWord(bytecode, x1);
outputByte(bytecode, y2); outputWord(bytecode, y1);
lineOkay = TRUE; outputWord(bytecode, x2);
break; outputWord(bytecode, y2);
lineOkay = TRUE;
break;
case PARSE_PLOT: case PARSE_RESET:
// Plot (value),(value) outputByte(bytecode, PARSE_RESET);
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break; lineOkay = TRUE;
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 319) break; break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
outputByte(bytecode, PARSE_PLOT);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
lineOkay = TRUE;
break;
case PARSE_RECTANGLE: } // switch
// Rectangle (value),(value) to (value),(value)
if (!parserGetXY(&tokenEnd, variables, &x1, &y1)) break;
if (!parserGetWord("TO", &tokenEnd)) 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;
if (IS_NUMBER(y1) && IS_NUMBER(y2)) if (y2 < y1) break;
if (IS_NUMBER(y1)) if (y1 < 0 || y1 > 199) break;
if (IS_NUMBER(y2)) if (y2 < 0 || y2 > 199) break;
outputByte(bytecode, PARSE_RECTANGLE);
outputWord(bytecode, x1);
outputWord(bytecode, y1);
outputWord(bytecode, x2);
outputWord(bytecode, y2);
lineOkay = TRUE;
break;
case PARSE_RESET: // Stop looking for this keyword - we handled it.
outputByte(bytecode, PARSE_RESET); break;
lineOkay = TRUE;
break;
} // switch } else {
// Keep looking until we find this keyword or run out of commands.
keyword++;
} // keyword match
// Stop looking for this keyword - we handled it. } // loop over commands
break;
} else { } // label
// Keep looking until we find this keyword or run out of commands.
keyword++;
} // keyword match
} // loop over commands } // math
} // label } // blank line
} // math
// Is everything still okay? // Is everything still okay?
if (!lineOkay) { if (!lineOkay) {
@ -567,7 +647,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
} }
// Move to next line. // Move to next line.
line = strtok_r(NULL, "\n", &lineEnd); line = strtoke(NULL, "\n", &lineEnd);
while (line != NULL && (line[0] == ' ' || line[0] == '\t')) line++;
lineNumber++; lineNumber++;
} // read program line } // read program line