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:
parent
4c644e0eaa
commit
5c5fdf3375
1 changed files with 331 additions and 250 deletions
581
src/vecparse.c
581
src/vecparse.c
|
@ -21,6 +21,7 @@
|
|||
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include "common.h"
|
||||
#include "vecparse.h"
|
||||
|
||||
|
@ -38,15 +39,21 @@ typedef struct OperatorsS {
|
|||
ParserMathT id;
|
||||
} 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 outputWord(VecByteCodeT *bytecode, unsigned short word);
|
||||
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x);
|
||||
static gboolean parserGetWord(char *word, 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 void ensureBufferSize(VecByteCodeT *bytecode, int needed);
|
||||
static void outputByte(VecByteCodeT *bytecode, unsigned short word);
|
||||
static void outputWord(VecByteCodeT *bytecode, unsigned short word);
|
||||
static gboolean parserGetNextValue(char *token, char **valueEnd, char **variables, int *x);
|
||||
static gboolean parserGetWord(char *word, 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 char *strtoke(char *str, const char *delim, char **savePtr);
|
||||
|
||||
|
||||
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?
|
||||
*x = -1;
|
||||
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) {
|
||||
// Set MSb to indicate it's a variable.
|
||||
index |= 0x8000;
|
||||
|
@ -159,7 +165,6 @@ static gboolean parserGetX(char **tokenEnd, char **variables, int *x) {
|
|||
// It's a variable. Do we know it?
|
||||
*x = -1;
|
||||
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) {
|
||||
// Set MSb to indicate it's a variable.
|
||||
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 keyword;
|
||||
char *line;
|
||||
|
@ -239,6 +297,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
|||
PointT p2;
|
||||
PointT *points = NULL;
|
||||
char **variables = NULL;
|
||||
LabelT *labels = NULL;
|
||||
int result = -1; // Returns -1 on success or line number of first error.
|
||||
KeywordsT commands[] = {
|
||||
{ "BOX", PARSE_BOX },
|
||||
|
@ -273,291 +332,312 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
|||
|
||||
// Parse code.
|
||||
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) {
|
||||
|
||||
printf("%d [%s]\n", lineNumber, line);
|
||||
|
||||
// Get the first token on the line.
|
||||
token = strtok_r(line, " ", &tokenEnd);
|
||||
|
||||
// Is this something we care about? It'll be math, a label, or a keyword.
|
||||
lineOkay = FALSE;
|
||||
|
||||
// Is it math?
|
||||
if (strlen(token) > 1 && token[0] == '%') {
|
||||
// Is this a blank line?
|
||||
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.
|
||||
// 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;
|
||||
} else { // blank line
|
||||
|
||||
// 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;
|
||||
//***DEBUG***
|
||||
if (math[keyword].id == MATH_ASSIGN) {
|
||||
for (y1=0; y1<arrlen(variables); y1++) {
|
||||
printf("Variable %d = %s\n", y1, variables[y1]);
|
||||
}
|
||||
}
|
||||
// Is it math?
|
||||
if (strlen(token) > 1 && token[0] == '%') {
|
||||
|
||||
// We're doing some kind of math.
|
||||
|
||||
// Look up variable index in table, or add it if needed.
|
||||
// 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;
|
||||
}
|
||||
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?
|
||||
if (strlen(token) > 1 && token[strlen(token) - 1] == ':') {
|
||||
} else { // doing math
|
||||
|
||||
// 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.
|
||||
keyword = 0;
|
||||
while (commands[keyword].command) {
|
||||
if (strcasecmp(commands[keyword].command, token) == 0) {
|
||||
// Have we already used this label?
|
||||
x2 = -1;
|
||||
for (x1 = 0; x1 < hmlen(labels); x1++) {
|
||||
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.
|
||||
switch (commands[keyword].id) {
|
||||
} else { // doing a label
|
||||
|
||||
case PARSE_NONE:
|
||||
// Won't happen, but silences an error.
|
||||
break;
|
||||
// It's a keyword.
|
||||
keyword = 0;
|
||||
while (commands[keyword].command) {
|
||||
if (strcasecmp(commands[keyword].command, token) == 0) {
|
||||
|
||||
case PARSE_BOX:
|
||||
// Box (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_BOX);
|
||||
outputWord(bytecode, x1);
|
||||
outputWord(bytecode, y1);
|
||||
outputWord(bytecode, x2);
|
||||
outputWord(bytecode, y2);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
// Yep! Gather arguments and generate bytecode.
|
||||
switch (commands[keyword].id) {
|
||||
|
||||
case PARSE_CIRCLE:
|
||||
// Circle (value) at (value),(value)
|
||||
if (!parserGetX(&tokenEnd, variables, &y2)) 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_NONE:
|
||||
// Won't happen, but silences an error.
|
||||
break;
|
||||
|
||||
case PARSE_CLEAR:
|
||||
outputByte(bytecode, PARSE_CLEAR);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
case PARSE_BOX:
|
||||
// Box (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_BOX);
|
||||
outputWord(bytecode, x1);
|
||||
outputWord(bytecode, y1);
|
||||
outputWord(bytecode, x2);
|
||||
outputWord(bytecode, y2);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
|
||||
case PARSE_COLOR:
|
||||
// Color (short)
|
||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
|
||||
outputByte(bytecode, PARSE_COLOR);
|
||||
outputByte(bytecode, x1);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
case PARSE_CIRCLE:
|
||||
// Circle (value) at (value),(value)
|
||||
if (!parserGetX(&tokenEnd, variables, &y2)) 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_COMMENT:
|
||||
// Eat the rest of the line.
|
||||
while (token != NULL) {
|
||||
token = strtok_r(NULL, " ", &tokenEnd);
|
||||
}
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
case PARSE_CLEAR:
|
||||
outputByte(bytecode, PARSE_CLEAR);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
|
||||
case PARSE_ELLIPSE:
|
||||
// Ellipse (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_ELLIPSE);
|
||||
outputWord(bytecode, x1);
|
||||
outputWord(bytecode, y1);
|
||||
outputWord(bytecode, x2);
|
||||
outputWord(bytecode, y2);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
case PARSE_COLOR:
|
||||
// Color (short)
|
||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||
if (IS_NUMBER(x1)) if (x1 < 0 || x1 > 15) break;
|
||||
outputByte(bytecode, PARSE_COLOR);
|
||||
outputByte(bytecode, x1);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
|
||||
case PARSE_FILL:
|
||||
// Fill (value),(value) {to (value}
|
||||
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)) {
|
||||
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_COMMENT:
|
||||
// Eat the rest of the line.
|
||||
while (token != NULL) {
|
||||
token = strtok_r(NULL, " ", &tokenEnd);
|
||||
}
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
|
||||
case PARSE_LABEL:
|
||||
// Won't happen.
|
||||
break;
|
||||
case PARSE_ELLIPSE:
|
||||
// Ellipse (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_ELLIPSE);
|
||||
outputWord(bytecode, x1);
|
||||
outputWord(bytecode, y1);
|
||||
outputWord(bytecode, x2);
|
||||
outputWord(bytecode, y2);
|
||||
lineOkay = TRUE;
|
||||
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.
|
||||
case PARSE_FILL:
|
||||
// Fill (value),(value) {to (value}
|
||||
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)) {
|
||||
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:
|
||||
// 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) {
|
||||
arrdel(points, 0);
|
||||
}
|
||||
arrfree(points);
|
||||
isOkay = FALSE;
|
||||
break;
|
||||
lineOkay = TRUE;
|
||||
}
|
||||
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) {
|
||||
arrdel(points, 0);
|
||||
}
|
||||
arrfree(points);
|
||||
break;
|
||||
|
||||
case PARSE_MATH:
|
||||
// Won't happen.
|
||||
break;
|
||||
|
||||
case PARSE_PALETTE:
|
||||
// Palette (short) AS (short),(short),(short)
|
||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||
if (!parserGetWord("AS", &tokenEnd)) 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;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case PARSE_MATH:
|
||||
// Won't happen.
|
||||
break;
|
||||
case PARSE_PLOT:
|
||||
// Plot (value),(value)
|
||||
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:
|
||||
// Palette (short) AS (short),(short),(short)
|
||||
if (!parserGetX(&tokenEnd, variables, &x1)) break;
|
||||
if (!parserGetWord("AS", &tokenEnd)) 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;
|
||||
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;
|
||||
break;
|
||||
case PARSE_RECTANGLE:
|
||||
// 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_PLOT:
|
||||
// Plot (value),(value)
|
||||
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_RESET:
|
||||
outputByte(bytecode, PARSE_RESET);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
|
||||
case PARSE_RECTANGLE:
|
||||
// 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;
|
||||
} // switch
|
||||
|
||||
case PARSE_RESET:
|
||||
outputByte(bytecode, PARSE_RESET);
|
||||
lineOkay = TRUE;
|
||||
break;
|
||||
// Stop looking for this keyword - we handled it.
|
||||
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.
|
||||
break;
|
||||
} // loop over commands
|
||||
|
||||
} else {
|
||||
// Keep looking until we find this keyword or run out of commands.
|
||||
keyword++;
|
||||
} // keyword match
|
||||
} // label
|
||||
|
||||
} // loop over commands
|
||||
} // math
|
||||
|
||||
} // label
|
||||
|
||||
} // math
|
||||
} // blank line
|
||||
|
||||
// Is everything still okay?
|
||||
if (!lineOkay) {
|
||||
|
@ -567,7 +647,8 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) {
|
|||
}
|
||||
|
||||
// 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++;
|
||||
} // read program line
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue