Added double type to language and ignored more files
This commit is contained in:
parent
b3ae08e1ba
commit
36a0542b80
2 changed files with 151 additions and 33 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
||||||
*.o
|
*.o
|
||||||
prompt
|
prompt
|
||||||
|
vgcore*
|
||||||
|
.vscode/*
|
||||||
|
|
176
prompt.c
176
prompt.c
|
@ -32,6 +32,7 @@ void add_history(char* unused) {}
|
||||||
|
|
||||||
typedef union numerr {
|
typedef union numerr {
|
||||||
long num;
|
long num;
|
||||||
|
double dec;
|
||||||
int err;
|
int err;
|
||||||
} NumErr;
|
} NumErr;
|
||||||
|
|
||||||
|
@ -42,27 +43,33 @@ typedef struct {
|
||||||
} lval;
|
} lval;
|
||||||
|
|
||||||
// Possible lispy value types
|
// Possible lispy value types
|
||||||
enum { LVAL_NUM, LVAL_ERR };
|
enum { LVAL_LONG, LVAL_DOUBLE, LVAL_ERR };
|
||||||
|
|
||||||
// Possible Error Types
|
// Possible Error Types
|
||||||
enum { LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM };
|
enum { LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM, LERR_BAD_ARG };
|
||||||
|
|
||||||
|
|
||||||
lval eval_uni(lval x, char* op);
|
lval eval_uni(lval x, char* op);
|
||||||
lval eval_op(lval x, char* op, lval y);
|
lval eval_op(lval x, char* op, lval y);
|
||||||
lval eval(mpc_ast_t* t);
|
lval eval(mpc_ast_t* t);
|
||||||
long max(long x, long y);
|
double max(double x, double y);
|
||||||
long min(long x, long y);
|
double min(double x, double y);
|
||||||
lval lval_num(long x);
|
lval lval_long(long x);
|
||||||
|
lval lval_double(double x);
|
||||||
lval lval_err(int x);
|
lval lval_err(int x);
|
||||||
void flval_print(FILE* stream, lval v);
|
void flval_print(FILE* stream, lval v);
|
||||||
void lval_print(lval v);
|
void lval_print(lval v);
|
||||||
void lval_println(lval v);
|
void lval_println(lval v);
|
||||||
|
size_t treeContentsLength(mpc_ast_t* t);
|
||||||
|
char* concatTreeContents(mpc_ast_t* t);
|
||||||
|
void concatNodeContents(char* stringToExtend, mpc_ast_t* t, size_t* currentLength);
|
||||||
|
|
||||||
int main (int argc, char** argv) {
|
int main (int argc, char** argv) {
|
||||||
|
|
||||||
// Create some parsers
|
// Create some parsers
|
||||||
mpc_parser_t* Number = mpc_new("number");
|
mpc_parser_t* Number = mpc_new("number");
|
||||||
|
mpc_parser_t* Long = mpc_new("long");
|
||||||
|
mpc_parser_t* Double = mpc_new("double");
|
||||||
mpc_parser_t* Operator = mpc_new("operator");
|
mpc_parser_t* Operator = mpc_new("operator");
|
||||||
mpc_parser_t* Expr = mpc_new("expr");
|
mpc_parser_t* Expr = mpc_new("expr");
|
||||||
mpc_parser_t* Lispy = mpc_new("lispy");
|
mpc_parser_t* Lispy = mpc_new("lispy");
|
||||||
|
@ -70,12 +77,14 @@ int main (int argc, char** argv) {
|
||||||
// Define them with the following language
|
// Define them with the following language
|
||||||
mpca_lang(MPCA_LANG_DEFAULT,
|
mpca_lang(MPCA_LANG_DEFAULT,
|
||||||
"\
|
"\
|
||||||
number : /-?[0-9]+/; \
|
number : /[0-9]+/; \
|
||||||
|
long : '-'? <number>; \
|
||||||
|
double : <long> '.' <number>; \
|
||||||
operator : '+' | '-' | '*' | '/' | '%' \
|
operator : '+' | '-' | '*' | '/' | '%' \
|
||||||
| '^' | \"min\" | \"max\"; \
|
| '^' | \"min\" | \"max\"; \
|
||||||
expr : <number> | '(' <operator> <expr>+ ')'; \
|
expr : (<double> | <long>) | '(' <operator> <expr>+ ')'; \
|
||||||
lispy : /^/ <operator> <expr>+ /$/; \
|
lispy : /^/ <operator> <expr>+ /$/; \
|
||||||
", Number, Operator, Expr, Lispy);
|
", Number, Long, Double, Operator, Expr, Lispy);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,6 +109,7 @@ int main (int argc, char** argv) {
|
||||||
// Evualuate the expression and print its output
|
// Evualuate the expression and print its output
|
||||||
lval result = eval(r.output);
|
lval result = eval(r.output);
|
||||||
lval_println(result);
|
lval_println(result);
|
||||||
|
// mpc_ast_print(r.output);
|
||||||
mpc_ast_delete(r.output);
|
mpc_ast_delete(r.output);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise print the error
|
// Otherwise print the error
|
||||||
|
@ -111,7 +121,7 @@ int main (int argc, char** argv) {
|
||||||
free(input);
|
free(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpc_cleanup(4, Number, Operator, Expr, Lispy);
|
mpc_cleanup(6, Number, Long, Double, Operator, Expr, Lispy);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,37 +129,93 @@ lval eval_op(lval x, char* op, lval y) {
|
||||||
if (x.type == LVAL_ERR) { return x; }
|
if (x.type == LVAL_ERR) { return x; }
|
||||||
if (y.type == LVAL_ERR) { return y; }
|
if (y.type == LVAL_ERR) { return y; }
|
||||||
|
|
||||||
if (strcmp(op, "+") == 0) { return lval_num(x.data.num + y.data.num); }
|
int resultType;
|
||||||
if (strcmp(op, "-") == 0) { return lval_num(x.data.num - y.data.num); }
|
if (x.type == LVAL_LONG && y.type == LVAL_LONG) {
|
||||||
if (strcmp(op, "*") == 0) { return lval_num(x.data.num * y.data.num); }
|
resultType = LVAL_LONG;
|
||||||
if (strcmp(op, "/") == 0) {
|
} else {
|
||||||
// If you try to divide by zero, report an error
|
resultType = LVAL_DOUBLE;
|
||||||
return y.data.num == 0 ? lval_err(LERR_DIV_ZERO) : lval_num(x.data.num / y.data.num);
|
}
|
||||||
|
|
||||||
|
double xVal;
|
||||||
|
if (x.type == LVAL_LONG) {
|
||||||
|
xVal = x.data.num;
|
||||||
|
} else {
|
||||||
|
xVal = x.data.dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
double yVal;
|
||||||
|
if (y.type == LVAL_LONG) {
|
||||||
|
yVal = y.data.num;
|
||||||
|
} else {
|
||||||
|
yVal = y.data.dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(op, "+") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(xVal + yVal) : lval_double(xVal + yVal);
|
||||||
|
}
|
||||||
|
if (strcmp(op, "-") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(xVal - yVal) : lval_double(xVal - yVal);
|
||||||
|
}
|
||||||
|
if (strcmp(op, "*") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(xVal * yVal) : lval_double(xVal * yVal);;
|
||||||
|
}
|
||||||
|
if (strcmp(op, "/") == 0) {
|
||||||
|
if (yVal == 0) { return lval_err(LERR_DIV_ZERO); }
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(xVal / yVal) : lval_double(xVal / yVal);
|
||||||
|
}
|
||||||
|
if (strcmp(op, "min") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(min(xVal, yVal)) : lval_double(min(xVal, yVal));
|
||||||
|
}
|
||||||
|
if (strcmp(op, "max") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(max(xVal, yVal)) : lval_double(max(xVal, yVal));
|
||||||
|
}
|
||||||
|
if (strcmp(op, "^") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(pow(xVal, yVal)) : lval_double(pow(xVal, yVal));
|
||||||
|
}
|
||||||
|
if (strcmp(op, "%") == 0) {
|
||||||
|
return (resultType == LVAL_LONG) ? lval_long(fmod(xVal, yVal)) : lval_double(fmod(xVal, yVal));
|
||||||
}
|
}
|
||||||
if (strcmp(op, "min") == 0) { return lval_num(min(x.data.num, y.data.num)); }
|
|
||||||
if (strcmp(op, "max") == 0) { return lval_num(max(x.data.num, y.data.num)); }
|
|
||||||
if (strcmp(op, "^") == 0) { return lval_num(pow(x.data.num, y.data.num)); }
|
|
||||||
if (strcmp(op, "%") == 0) { return lval_num(fmod(x.data.num, y.data.num)); }
|
|
||||||
|
|
||||||
return lval_err(LERR_BAD_OP);
|
return lval_err(LERR_BAD_OP);
|
||||||
}
|
}
|
||||||
|
|
||||||
lval eval_uni(lval x, char* op) {
|
lval eval_uni(lval x, char* op) {
|
||||||
|
|
||||||
// If it's an error, return it
|
// If it's an error, return it
|
||||||
if (x.type == LVAL_ERR) { return x; }
|
if (x.type == LVAL_ERR) { return x; }
|
||||||
|
|
||||||
if (strcmp(op, "-") == 0) { return lval_num(-1 * x.data.num); }
|
double xVal = (x.type == LVAL_LONG) ? x.data.num : x.data.dec;
|
||||||
|
|
||||||
|
if (strcmp(op, "-") == 0) { return (x.type == LVAL_LONG) ? lval_long(-1 * xVal) : lval_double(-1 * xVal); }
|
||||||
|
|
||||||
return lval_err(LERR_BAD_OP);
|
return lval_err(LERR_BAD_OP);
|
||||||
}
|
}
|
||||||
|
|
||||||
lval eval(mpc_ast_t* t) {
|
lval eval(mpc_ast_t* t) {
|
||||||
// If tagged as a number, return directly
|
if (strstr(t->tag, "long")) {
|
||||||
if (strstr(t->tag, "number")) {
|
// Grab the contents of all the nodes in the tree otherwise you might not get the string you expect
|
||||||
|
char* treeString = concatTreeContents(t);
|
||||||
|
|
||||||
// Check to see if there's some error in conversion
|
// Check to see if there's some error in conversion
|
||||||
errno = 0;
|
errno = 0;
|
||||||
long x = strtol(t->contents, NULL, 10);
|
long x = strtol(treeString, NULL, 10);
|
||||||
return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM);
|
|
||||||
|
// Free the memory allocated in treestring since it's no longer needed
|
||||||
|
free(treeString);
|
||||||
|
|
||||||
|
return errno != ERANGE ? lval_long(x) : lval_err(LERR_BAD_NUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(t->tag, "double")) {
|
||||||
|
char* treeString = concatTreeContents(t);
|
||||||
|
|
||||||
|
// Check to see if there's some error in conversion
|
||||||
|
errno = 0;
|
||||||
|
double x = strtod(treeString, NULL);
|
||||||
|
|
||||||
|
free(treeString);
|
||||||
|
|
||||||
|
return errno != ERANGE ? lval_double(x) : lval_err(LERR_BAD_NUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The operator is always the second child
|
// The operator is always the second child
|
||||||
|
@ -174,27 +240,34 @@ lval eval(mpc_ast_t* t) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
long max(long x, long y) {
|
double max(double x, double y) {
|
||||||
if (x > y) {
|
if (x > y) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
long min(long x, long y) {
|
double min(double x, double y) {
|
||||||
if (x < y) {
|
if (x < y) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
lval lval_num(long x) {
|
lval lval_long(long x) {
|
||||||
lval v;
|
lval v;
|
||||||
v.type = LVAL_NUM;
|
v.type = LVAL_LONG;
|
||||||
v.data.num = x;
|
v.data.num = x;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lval lval_double(double x) {
|
||||||
|
lval v;
|
||||||
|
v.type = LVAL_DOUBLE;
|
||||||
|
v.data.dec = x;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
lval lval_err(int x) {
|
lval lval_err(int x) {
|
||||||
lval v;
|
lval v;
|
||||||
v.type = LVAL_ERR;
|
v.type = LVAL_ERR;
|
||||||
|
@ -204,8 +277,11 @@ lval lval_err(int x) {
|
||||||
|
|
||||||
void flval_print(FILE* stream, lval v) {
|
void flval_print(FILE* stream, lval v) {
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
// If it's a number, then print it out
|
// If it's an integer, then print it out
|
||||||
case LVAL_NUM: fprintf(stream, "%li", v.data.num); break;
|
case LVAL_LONG: fprintf(stream, "%li", v.data.num); break;
|
||||||
|
|
||||||
|
// Do the same for doubles
|
||||||
|
case LVAL_DOUBLE: fprintf(stream, "%lf", v.data.dec); break;
|
||||||
|
|
||||||
// If it's an error, indicate the error
|
// If it's an error, indicate the error
|
||||||
case LVAL_ERR:
|
case LVAL_ERR:
|
||||||
|
@ -227,4 +303,44 @@ void lval_print(lval v) { flval_print(stdout, v); }
|
||||||
|
|
||||||
void lval_println(lval v) { lval_print(v); putchar('\n'); }
|
void lval_println(lval v) { lval_print(v); putchar('\n'); }
|
||||||
|
|
||||||
|
size_t treeContentsLength(mpc_ast_t* t) {
|
||||||
|
size_t result = strlen(t->contents);
|
||||||
|
if (t->children_num == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < t->children_num; i++) {
|
||||||
|
result += treeContentsLength(t->children[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* concatTreeContents(mpc_ast_t* t) {
|
||||||
|
// Calculate size needed for the string
|
||||||
|
size_t totalLength = treeContentsLength(t);
|
||||||
|
|
||||||
|
// Allocate memory for string and null terminator
|
||||||
|
char* stringToExtend = malloc(totalLength + 1);
|
||||||
|
// [TODO] Write an allocation error handler
|
||||||
|
|
||||||
|
size_t currentLength = 0;
|
||||||
|
concatNodeContents(stringToExtend, t, ¤tLength);
|
||||||
|
|
||||||
|
stringToExtend[totalLength] = '\0';
|
||||||
|
|
||||||
|
return stringToExtend;
|
||||||
|
}
|
||||||
|
|
||||||
|
void concatNodeContents(char* stringToExtend, mpc_ast_t* t, size_t* currentLength) {
|
||||||
|
size_t leafLength = strlen(t->contents);
|
||||||
|
|
||||||
|
memcpy(stringToExtend + (*currentLength), t->contents, leafLength);
|
||||||
|
*currentLength = *currentLength + leafLength;
|
||||||
|
|
||||||
|
if (t->children_num != 0) {
|
||||||
|
for (int i = 0; i < t->children_num; i++) {
|
||||||
|
concatNodeContents(stringToExtend, t->children[i], currentLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Reference in a new issue