diff --git a/appendix_a_hand_rolled_parser.html b/appendix_a_hand_rolled_parser.html index abac8f5..ebf3fcf 100644 --- a/appendix_a_hand_rolled_parser.html +++ b/appendix_a_hand_rolled_parser.html @@ -1,4 +1,4 @@ -
Can I do this if I've not finished the book?
- +If you've not completed all the chapters of this book it is probably not a good idea to attempt this appendix. It may be possible to complete this appendix if you're already past Chapter 9 • S-Expressions, but if you're not completed this chapter already it might not make much sense. Sorry!
lval* builtin_load(lenv* e, lval* a) {
LASSERT_NUM("load", a, 1);
LASSERT_TYPE("load", a, 0, LVAL_STR);
-
+
/* Open file and check it exists */
FILE* f = fopen(a->cell[0]->str, "rb");
if (f == NULL) {
@@ -55,7 +55,7 @@ Replacing mpc
lval_del(a);
return err;
}
-
+
/* Read File Contents */
fseek(f, 0, SEEK_END);
long length = ftell(f);
@@ -71,7 +71,7 @@ Replacing mpc
int pos = 0;
lval* expr = lval_read_expr(input, &pos, '\0');
free(input);
-
+
/* Evaluate all expressions contained in S-Expr */
if (expr->type != LVAL_ERR) {
while (expr->count) {
@@ -82,10 +82,10 @@ Replacing mpc
} else {
lval_println(expr);
}
-
- lval_del(expr);
+
+ lval_del(expr);
lval_del(a);
-
+
return lval_sexpr();
}
@@ -113,9 +113,9 @@ For now let us assume the next character isn't the end
character. The first thing we need to check is that we've not reached the end of the input. If we've reached the end of the input without encountering the end
character then we can throw a syntax error and jump to the end of the input to ensure no more is consumed.
int lval_read_expr(lval* v, char* s, int i, char end) {
-
+
while (s[i] != end) {
-
+
/* If we reach end of input then there is some syntax error */
if (s[i] == '\0') {
lval_add(v, lval_err("Missing %c at end of input", end));
@@ -151,7 +151,7 @@ A Character at a Time
i = lval_read_expr(x, s, i+1, ')');
continue;
}
-
+
/* If next character is { then read Q-Expr */
if (s[i] == '{') {
lval* x = lval_qexpr();
@@ -188,7 +188,7 @@ A Character at a Time
lval_add(v, lval_err("Unknown Character %c", s[i]));
return strlen(s)+1;
}
-
+
return i+1;
}
@@ -197,21 +197,21 @@ Reading in symbols is fairly straight forward. We start by allocating some -empty string, and then, for each character in the input which is valid as part +
Reading in symbols is fairly straight forward. We start by allocating some +empty string, and then, for each character in the input which is valid as part of a symbol we append this character to the string.
int lval_read_sym(lval* v, char* s, int i) {
-
+
/* Allocate Empty String */
char* part = calloc(1,1);
-
+
/* While valid identifier characters */
while (strchr(
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789_+-*\\/=<>!&", s[i]) && s[i] != '\0') {
-
+
/* Append character to end of string */
part = realloc(part, strlen(part)+2);
part[strlen(part)+1] = '\0';
@@ -220,8 +220,8 @@ Reading Symbols
}
-You'll notice that we're also reading in numbers with this code. So the next -step is to check if this symbol is actually a number. To do this we just check +
You'll notice that we're also reading in numbers with this code. So the next +step is to check if this symbol is actually a number. To do this we just check if all of the characters are digits.
/* Check if Identifier looks like number */
@@ -232,7 +232,7 @@ Reading Symbols
Finally, if the symbol is a number we convert it with similar code to the
-previous code we used when we were reading from the mpc
AST, or otherwise we just use it as a normal symbol. Then we free
the
+previous code we used when we were reading from the mpc
AST, or otherwise we just use it as a normal symbol. Then we free
the
temporary string we allocated and return the new position in the input.
/* Add Symbol or Number as lval */
@@ -243,10 +243,10 @@ Reading Symbols
} else {
lval_add(v, lval_sym(part));
}
-
+
/* Free temp string */
free(part);
-
+
/* Return updated position in input */
return i;
}
@@ -313,12 +313,12 @@ Reading Strings
With these we can begin to write our functions for reading strings. First we allocate a temporary string and while we're not reading the terminal "
character we're going to process the incoming characters.
int lval_read_str(lval* v, char* s, int i) {
-
+
/* Allocate empty string */
char* part = calloc(1,1);
-
+
while (s[i] != '"') {
-
+
char c = s[i];
@@ -332,13 +332,13 @@ Reading Strings
}
-We then check if the next character is a backslash. If we have a backslash then we need to escape the next character after it. Given the previous functions we're already defined this is easy. If it is unescapable then we unescape it - otherwise we throw some error.
+We then check if the next character is a backslash. If we have a backslash then we need to escape the next character after it. Given the previous functions we're already defined this is easy. If it is unescapable then we unescape it - otherwise we throw some error.
/* If backslash then unescape character after it */
if (c == '\\') {
i++;
/* Check next character is escapable */
- if (strchr(lval_str_unescapable, s[i])) {
+ if (strchr(lval_str_unescapable, s[i])) {
c = lval_str_unescape(s[i]);
} else {
lval_add(v, lval_err("Invalid escape character %c", c));
@@ -355,14 +355,14 @@ Reading Strings
part = realloc(part, strlen(part)+2);
part[strlen(part)+1] = '\0';
part[strlen(part)+0] = c;
- i++;
+ i++;
}
-
+
/* Add lval and free temp string */
lval_add(v, lval_str(part));
-
+
free(part);
-
+
return i+1;
}
@@ -403,13 +403,13 @@ /* Parser Declariations */
-mpc_parser_t* Number;
-mpc_parser_t* Symbol;
-mpc_parser_t* String;
+mpc_parser_t* Number;
+mpc_parser_t* Symbol;
+mpc_parser_t* String;
mpc_parser_t* Comment;
-mpc_parser_t* Sexpr;
-mpc_parser_t* Qexpr;
-mpc_parser_t* Expr;
+mpc_parser_t* Sexpr;
+mpc_parser_t* Qexpr;
+mpc_parser_t* Expr;
mpc_parser_t* Lispy;
@@ -421,7 +421,7 @@ A Polish Nobleman • A typical Polish Notation user
+A typical Polish Notation user
Please enter your download password.