Code Monkey home page Code Monkey logo

buildyourownlisp's Issues

how to support float number

number : /-?[0-9]*[.]?[0-9]+/ ; could not,

lispy> + 1 2
No you're a + 1 2
<stdin>:1:4: error: expected one of '0123456789', one of '.' or one or more of one of '0123456789' at space
lispy> ^DNo you're a (null)
Segmentation fault

I want to add float support.

Loading files

I'm probably missing something ridiculously obvious, but whenever I try to load a file after finishing Chapter 14, I get the error:

Error: Could not load Library hello.lspy:1:23: error: expected '-', one or more of one of '0123456789', one or more of one of 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+-*/\=<>!&', '"', ';', '(', '{', newline or end of input at end of input

hello.lspy in this case contained (print "Hello World!")

Any idea what I'm doing wrong?

can't understand grammar definition problem

Hi,

I'm trying to define a grammar for an esoteric lang called Wittgen as an exercise of chapter 6 of your book, but I can't understand what is wrong with this grammar definition:


mpc_parser_t* Variable        = mpc_new("variable");
mpc_parser_t* Assign_Operator = mpc_new("assign");
mpc_parser_t* Remind_Operator = mpc_new("remind");
mpc_parser_t* Expr            = mpc_new("expr");
mpc_parser_t* Envinronment    = mpc_new("envinronment");

mpca_lang(MPCA_LANG_DEFAULT,
  " variable     : /[a-zA-Z0-9]+/ ;"                                                     
  " assign       : '+' ;"                                         
  " remind       : '@' ;"                                                                
  " expr         : <variable> | <remind> <variable> '}' | <variable> <assign> <expr>+ '}' ;"
  " envinronment : /^/<expr>+/$/ ;",
  Variable, Assign_Operator, Remind_Operator, Expr, Envinronment);

it works for the simple variable, and for the remind operator, but the assignment function "foo=foobar}" exits with this error:

WITTGEN> ale=ale} <stdin>:1:4: error: expected one of 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', one or more of one of 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', '@' or end of input at '='

question about conditional evaluation

Just curious, is there a convention for when something should or should not have delayed evaluation?

Your conditional implementation takes 3 args, the first is the conditional as an s-expression and the other two are q-expressions.

Why aren't all the arguments q-expressions with the conditional evaluated in builtin_if?

I only ask this because when I built my conditional (before reading yours) I made all the arguments q-expressions and evaluated them in builtin_if one by one.

I sort of understand why the functions for the condition are q-expressions: you want the "if" operator to execute them later if necessary.

Chapter 15

line 360 and 361,

(def {curry} {unpack})

curry should be a symbol, not a Q-expression. So it should be

(def {curry} unpack)

As well as uncurry.

line 390,
“Minimum of Arguments” -> “Maximun of Arguments”

Needing a hint (please)

First of all, thank you for the tutorial. It is wonderful.

Second, I would appreciate a hint on how to proceed to implement the check to guard against redefining an internal function.

I continue to work through it and after completing the variables chapter had code that worked to prevent the redefinition of an internal variable. However, this approach was broken when I implemented the basic functions code and I haven't been able to figure out a better and workable approach. Below is a link to a snapshot of where I am at. I believe the approach has to be to add a check for 'builtin' in lvar as not NULL within the 'builtin_var' function at the point where I currently have the 'printf' to list the symbol being scanned (line 988).

https://github.com/ptdecker/lispy/blob/8cd829339587eeeb78cc39b47c68347fcf50c9b0/functions.c

editline/history

I'm having trouble in chapter 4 using editline/history.

I'm using mac osx 10.9. I get 'editline/history.h' file not found as mentioned in your text. Unfortunately, I cant get it to work. When I try to install using brew it says its already installed. So I have downloaded and compiled/installed readline and editline. They both have files found in /usr/local/lib but I get the same error.

I know I could just comment it out and move on but I really want to figure this out. Any advice for us osx users?

Thank you.

Erroneous 'whitespace' in printed AST in chapter6_parsing.html

In the examples of correct output from the parser it says I should get:

lispy> hello
<stdin>:1:1: error: expected whitespace, '+', '-', '*' or '/' at 'h'
lispy> / 1dog
<stdin>:1:4: error: expected one of '0123456789', whitespace, '-', one or more of one of '0123456789', '(' or end of input at 'd'

But I get:

lispy> hello
<stdin>:1:1: error: expected '+', '-', '*' or '/' at 'h'
lispy> / 1dog
<stdin>:1:4: error: expected one of '0123456789', '-', one or more of one of '0123456789', '(' or end of input at 'd'

You version includes 'whitespace' in the 'expected one of ...' in output for 'hello' and '/ 1dog' and this is not included in the actual program output.

I thought I might have made a typo when typing the program so I downloaded your version of parsing at the end of the chapter, compiled this instead of my version and the difference remains.

I'm using gcc 4.8.5 on Ubuntu Linux 14.04 and the version of mpc.h and mpc.c that I downloaded from the Github repo tonight (17 may).

Chapter 11 feels like it's missing some steps

The source code contains a few changes not explicitly pointed out in the chapter:

  1. builtin_add/sub/mul etc...
  2. adding env to existing builtins (and may be worth noting why env isn't used in them but included anyways)
  3. the "optional" type checking macros in the source and are used in later chapters but only presented as a post-chapter challenge

Isn't using Flex/Bison pair is the best choice for input ?

I'm surprized why you don't use flex/bison for input parsing ?
It's basic tools included in all toolchains and widely used for text data parsing.
What advantages does mpc have over bison-generated parser (except illustration of using an external library in C programming) ?

Lisp syntax without ( ) at start and end

Hi,

I am reading your book and maybe this is a noob question, but I would like to create a language syntax that doesn't require () at the start and the end. Example:

Actual syntax
(def {s} = 3)

Syntax that I want
def {s} = 3

The same with order in math operations:

Actual syntax
(+ 4 5)

Syntax that I want
(3 + 5)

Small typo

Hey, I spotted a little typo here.

I believe

In other cases it may modify the input lval* and the return it.

should be:

In other cases it may modify the input lval* and the return it.

I can send a pull request if needed, just wouldn't think it would be of importance.

Keep up the good work!

Compile time error for Chapter 8's "error_handling.c" on OSX

File is error_handling.c from chapter 8, mpc.c and mpc.h are in the local direcotry.

Compiling with cc -std=c99 -Wall error_handling.c -ledit -lm -v -o error_handling on OSX Yosemite (10.10.4) yields the following invocation:

Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.10.0 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name error_handling.c -mrelocation-model pic -pic-level 2 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 242.2 -v -dwarf-column-info -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.1.0 -Wall -std=c99 -fdebug-compilation-dir /Users/ron/Development/build-your-own-lisp/chpt_8 -ferror-limit 19 -fmessage-length 115 -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.10.0 -fencode-extended-block-signature -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/z6/jl998_mx7rz2s6l38795ygfr0000gq/T/error_handling-330a97.o -x c error_handling.c
clang -cc1 version 6.1.0 based upon LLVM 3.6.0svn default target x86_64-apple-darwin14.4.0
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.1.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.10.0 -o error_handling /var/folders/z6/jl998_mx7rz2s6l38795ygfr0000gq/T/error_handling-330a97.o -ledit -lm -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.1.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
  "_mpc_ast_delete", referenced from:
      _main in error_handling-330a97.o
  "_mpc_err_delete", referenced from:
      _main in error_handling-330a97.o
  "_mpc_err_print", referenced from:
      _main in error_handling-330a97.o
  "_mpc_new", referenced from:
      _main in error_handling-330a97.o
  "_mpc_parse", referenced from:
      _main in error_handling-330a97.o
  "_mpca_lang", referenced from:
      _main in error_handling-330a97.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

flask-mail new import convention

Hey there, thanks for the nice course. One issue I noticed with the flask webserver is the import convention for flask-mail is using an older convention that will not successfully import on newer versions of flask.

Issue:

flask.ext.mail is a retired namespace. New namespace is flask_mail

How to reproduce:

In a fresh python 3 environment with the latest version of flask, attempt to import with the from flask.ext.mail import Mail, Message. This throws the following error:

ModuleNotFoundError: No module named 'flask.ext'

Resolution:

The easiest step to resolve would be swap the from flask.ext.mail import Mail, Message to from flask_mail import Mail, Message. This is the new convention and I have confirmed it works on my machine with a fresh Python 3, latest Flask, and Pip environment. Only issue with this is it could cause issues with your web server if you use this code for it.

Another way to resolve would be to include a requirements.txt pip file.

Thoughts on which route you would like to go? I can open a PR if needed.

Thanks!

Sam

Minor errata with online text, Chapter 14

When I tried to run the code at the "Reading Strings" section, it gave me the error "Segmentation Fault: 11". I tried running this on an Ubuntu EC2 instance, and it gave me <stdin>:1:1: error: expected '-', one or more of one of '0123456789', one or more of one of 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+-*/\=<>!&', '(', '{' or end of input at '"'

I fixed this by declaring within int main() mpc_parser_t* String = mpc_new("string"), making sure that expr has <string> as part of its accepted values, making sure String was included within the scope of the mpca_lang declaration, and adding it to the mpc_cleanup() function.

In chapter 9, some code may be unneeded

I am following the book(great resource!), and in chapter 9, in function lval_read, I think the lines
if (strcmp(t->children[i]->contents, "}") == 0) { continue; }
if (strcmp(t->children[i]->contents, "{") == 0) { continue; }

are from the following chapter on q-expr. Till now "{" or "}" are not in the language defined by the parser.

Also, I am not sure about the "regex" in the following line, as it also isn't defined. I assume these lines will never be executed, so don't really cause a problem, but are somewhat confusing.

In the git repo, these lines will be from https://github.com/orangeduck/BuildYourOwnLisp/blob/master/chapter9_s_expressions.html#L270

Same change on the source code at https://github.com/orangeduck/BuildYourOwnLisp/blob/master/src/s_expressions.c#L261
as well.
I think a patch would be just removing these lines? I can submit a pull request, if this seems correct.

chapter 4 editline library - not installed by default

In Ubuntu the editline library is not installed by default. It may the case in most linux distros.
One must install it manually by the command:

sudo apt-get install libedit-dev

Please mention this in Chapter 4 under the corresponding heading so that others can find that easily.

Correction concerning double pointers in Chapter 7

In Chapter 7, when discussing the mpc_ast_t struct, you say

The type of the children field is mpc_ast_t**. This is a double pointer type we've not seen before. 

However, we have seen a double pointer before, in the main function arguments:

int main(int argc, char** argv)

Figured I'd throw this out there in case you wanted to reword the Chapter 7 text or even reference back to the main() function's argv argument at this point.

There is a problem in the code for conditionals.c

You write a good tutorial, I learned a lot. But the symbols in lines 641 through 644 are escaped:

  lenv_add_builtin(e, "&gt;",  builtin_gt);
  lenv_add_builtin(e, "&lt;",  builtin_lt);
  lenv_add_builtin(e, "&gt;=", builtin_ge);
  lenv_add_builtin(e, "&lt;=", builtin_le);

they should be:

  lenv_add_builtin(e, ">",  builtin_gt);
  lenv_add_builtin(e, "<",  builtin_lt);
  lenv_add_builtin(e, ">=", builtin_ge);
  lenv_add_builtin(e, "<=", builtin_le);

rlwrap

Hello!

I'm enjoying your book so far. I'm only up to Chapter 4.

Starting here: https://github.com/orangeduck/BuildYourOwnLisp/blob/master/chapter4_interactive_prompt.html#L121 ... I see you're pulling in libedit.

Well, have you considered rlwrap?

rlwrap runs the specified command, intercepting user input in order to provide readline's line editing, persistent history and completion.

Before I got to the libedit part of your book, I had run the first version of prompt.c a few times to see what happens if I input more than 2048 characters. Without really thinking about it, I ctrl+c'd out and ran rlwrap ./prompt instead... It worked fine. My arrow up key performs the expected action, and ctrl+a moves my cursor to the beginning of the line, etc...

I see that you also use the introduction of libedit as subject matter for the next lesson: how to use import and pull a library in during compile...

So, I dunno, I guess this bug might be pointless. It's certainly not a "bug" for that matter.

But I hope it helps somebody in some way. I'll skip libedit going forward and report back if it causes me any problems.

Cheers, and thanks for the book!
--Dave

double free in Chapter 9

lval_del(y) is called twice here, in the case of a division by 0 error:

  while (a->count > 0) {

    /* Pop the next element */
    lval* y = lval_pop(a, 0);

    if (strcmp(op, "+") == 0) { x->num += y->num; }
    if (strcmp(op, "-") == 0) { x->num -= y->num; }
    if (strcmp(op, "*") == 0) { x->num *= y->num; }
    if (strcmp(op, "/") == 0) {
      if (y->num == 0) {
        lval_del(x); lval_del(y);
        x = lval_err("Division By Zero!"); break;
      }
      x->num /= y->num;
    }

    lval_del(y);
  }

editline header files not found in Ubuntu (Cloud9 IDE)

I'm following the book on Cloud9 IDE. I'm unable to compile with editline headers included.

san:~/workspace (master) $ sudo apt-get install build-essential
Reading package lists... Done
Building dependency tree       
Reading state information... Done
build-essential is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 35 not upgraded.
san:~/workspace (master) $ make lispy
cc     lispy.c   -o lispy
lispy.c:4:31: fatal error: editline/readline.h: No such file or directory
 #include <editline/readline.h>
                               ^
compilation terminated.
make: *** [lispy] Error 1

Below is my code:

#include <stdio.h>
#include <stdlib.h>

#include <editline/readline.h>
#include <editline/history.h>

int main(int argc, char** argv) {

    // Version and Instructions to quit
    puts("Lispy Version 0.0.0.0.1");
    puts("Press ^C (Ctrl + C) to quit");


    while(1) {
        char *input = readline("lispy> ");
        add_history(input);
        printf("No, you're a %s\n", input);
        free(input);
    }

    return 0;
}

builtin_load causes segfault

So, I'm on chapter 14 now, and I cannot for the life of me figure out this error I'm getting.
I finished the chapter, and everything seems to be working fine except the load function - whenever I use it I get a segfault.
I quickly fired up gdb, and the error message is:
" Program received signal SIGSEGV, Segmentation fault.
0x00000000004070fb in mpc_parse_input (i=0x63a210, init=0x0, final=0x7fffffffe570) at mpc.c:983
983 switch (p->type) { "
I then compiled and ran your completed version through gdb to inspect the variables up to that point and I see that init appears to be the parser pointer to Lispy, as opposed to the NULL my program gives up.
I've compared our code and it's mostly the same save for a few things that i've added in previous chapters, but those shouldn't cause problems seeing as the language works fine outside of the load function (is this a correct assumption?).
Any help would be appreciated.

EDIT: I'm on linux, and I have the code in a repo here, although I haven't updated it in a while since I'm mostly writing this for myself. If necessary, I can commit the latest changes.

Different Solution

I was working through this and came up with a rather different solution -- I don't think the algorithm, if that's the right word to describe it, is quite the same? Any thoughts on this in terms of best practices? I think yours is definitely much nicer to read...

int evaluate(mpc_ast_t* t) {
    if (strstr(t->tag, "numeral") != 0) {
        return atoi(t->contents);
    } else {
        // seems like the loops is needed here when working your way in to terms on the right.  Perhaps the loop could be replaced with an if check.
        for (int i = 0; i < t->children_num; i++) {
            if (strcmp(t->children[i]->contents,"+") == 0) {
                return atoi(t->children[i+1]->contents) + evaluate(t->children[i+2]);
            } else if (strcmp(t->children[i]->contents, "-") == 0) {
                return atoi(t->children[i+1]->contents) - evaluate(t->children[i+2]);
            } else if (strcmp(t->children[i]->contents, "*") == 0) {
                return atoi(t->children[i+1]->contents) * evaluate(t->children[i+2]);
            } else if (strcmp(t->children[i]->contents, "/") == 0) {
                return atoi(t->children[i+1]->contents) / evaluate(t->children[i+2]);
            }
        }
    }
}

[chap 9] invalid struct definition using clang

loving the book

when i was reformatting in chapter nine and added the line struct lval** cell to the struct definition, my version of clang [Apple LLVM version 9.1.0 (clang-902.0.39.1)] threw a bunch of warnings and the following error:

lval.c:123:19: error: incomplete definition of type 'struct lval'
    if (v->cell[i]->type == LVAL_ERR) { return lval_take(v, i); }
        ~~~~~~~~~~^

and this note:

./lval.h:14:10: note: forward declaration of 'struct lval'
  struct lval** cell;

which led me to believe that line of the struct definition was being parsed as its own struct definition.

i fixed this by changing the definition and forward declaring the struct like so:

typedef struct lval lval;

struct lval {
  int type;
  long num;
  /* error and symbol types with string data */
  char *err;
  char *sym;
  /* count and pointer to a list of lval* */
  int count;
  lval** cell;
};

On description of for loop in Chapter 3

I am confused about some part in Chapter 3 of this otherwise easy-to-follow book. Chapter 3 has this paragraph:

The second kind of loop is a for loop. Rather than a condition, this loop requires three expressions separated by semicolons ;. These are an initialiser, a condition and an incrementer. The initialiser is performed before the loop starts, the condition is checked at the end of each iteration of the loop, and if false the loop is exited. The incrementer is performed before the next iteration of the loop.

Aren't things swapped around in the last sentence? I think the following sentence might be the right one

the condition is checked before each iteration of the loop, and if false the loop is exited. The incrementer is performed at the end of each iteration of the loop.

Book is not responsive on iOS

I love to read on my phone and the online version of the book doesn't responsively adapt to my phone's screen. I have to constantly zoom in and scan to make it legible. I started to do a pull request to see if I could figure it out myself. But I'm at work and my 5-10 minutes of exploring didn't yield quick results. :)

Warn about `-ledit` sooner

When reading chapter 4, I tried to compile and then went to research why compilation might be failing for me. It was only after I got it to compile that I scrolled to the next section and saw that you had explained about -ledit.

I suspect this is probably somewhat common among readers, so it might be worth addressing it in a different way. With that being said, I'm really enjoying the book so far. Thanks a lot

Errata with online text, Chapter 10

Well I got driven crazy over the last two days trying to find out a bug, and I fixed it and thought other people might benefit from this. I was getting a segmentation fault (core dump) in chapter_10 when trying to read in q_expressions, and on macOS Sierra it doesn't support valgrind and I tried/failed to use gdb (apparently I needed to install it from source, and then had to sign it using Apple's keychain access...went with EC2 instance instead).

The bug was that in lval_read(), not only do you need to add in
if (strstr(t->tag, "qexpr")) { x = lval_qexpr(); },

but you also needed to add

        if (strcmp(t->children[i]->contents, "{") == 0) { continue; }
        if (strcmp(t->children[i]->contents, "}") == 0) { continue; }

Otherwise it can't parse the '{' and '}' correctly.

At least it's in the reference file, which is where I got this :)

and coming fresh from JS, gdb and valgrind sure are barebones...

editline includes on OS X

The header editline/history does not exist on OS X. Including editline/readline seems to suffice.

A minimal, hacky fix would be to rewrite the #else branch of #ifdef _WIN32 to :

#ifdef _WIN32
//All the win-specific stuff
#else
#include <editline/readline.h>

#ifndef __APPLE__
#include <editline/history.h>
#endif
#endif

which fixes it for me(OS X 10.10).

string escaping/unescaping

I am probably doing something stupid, but I noticed that doing something like:

lispy> "hello\0world"
"helloworld"

Why isn't this reading "hello\0world" like other escaped strings? Poking at the mpc code, it looks like this should be dealt with.

Separately, the string "" doesn't work and things like "hello\Qnothing" end up "hello\Qnothing"

I'm assuming that the intent here is to store and print strings literally as they're entered (subverting things that may make printf format the string). If this is the case, then the above are issues, if not, then I'm just confused a bit :)

mpc.c contains diff info

For example:

static void mpc_input_mark(mpc_input_t *i) {
  
  if (i->backtrack < 1) { return; }
  
  i->marks_num++;
<<<<<<< HEAD
  
  if (i->marks_num > i->marks_slots) {
    i->marks_slots = i->marks_num + i->marks_num / 2;
    i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_slots);
    i->lasts = realloc(i->lasts, sizeof(char) * i->marks_slots);
  }

=======
  i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_num);
  i->lasts = realloc(i->lasts, sizeof(char) * i->marks_num);
>>>>>>> 9f9925ba69dda75ffc204da4c7809d793510885f
  i->marks[i->marks_num-1] = i->state;
  i->lasts[i->marks_num-1] = i->last;
  
  if (i->type == MPC_INPUT_PIPE && i->marks_num == 1) {
    i->buffer = calloc(1, 1);
  }
  
}

Consider rewriting for gitbook

The current version is a little sparse on style and a bit messy to edit. Turning the html into markdown and rendering it with gitbook would allow code highlighting and an easy way to view the book on github.

Minor Errata with Chapter 12

I was getting an issue after completing the initial function: Error: Unbound Symbol '\'. I looked at the source code and I realized I needed to add lenv_add_builtin(e, "\\", builtin_lambda) to lenv_add_builtins and that it wasn't being called anywhere else. Everything else works 🐼 💯

chapter 4: Possible memory bug in readline for Windows

Hi,

I really enjoy your book so far. I just found a memory bug in the readline code for Windows. The critical code is:

  char* cpy = malloc(strlen(buffer)+1);
  strcpy(cpy, buffer);
  cpy[strlen(cpy)-1] = '\0';

strcpy is already copying the string limiting '\0' correctly.
Setting it explicitly with cpy[strlen(cpy)-1] = '\0'; is unnecessary and you set it a character before the end.
So you always have two '\0' characters at the end of cpy.
Is this intended? It wasn't explained.

If strcpy wouldn't copy the '\0' there would be a memory bug since strlen would need it before you set it. The correct line would be:

  cpy[strlen(buffer)-1] = '\0';

But of course you have just done that two lines before. So storing it in a variable would be nicer (strlen is quite expensive!).

I have simply removed that line from my code. :-)

Thanks a lot for the nice book!

P.S.: I don't have a Windows machine either. :-)

malloc in lval_copy

Shouldn't the malloc for strings/errors read:
malloc(sizeof(char) * (strlen(v->err)+1)) not just malloc(strlen(v->err)+1) ?

Chapter 8 LERR_BAD_OP will not fire

Instead it will default to using the mpc error instead, trying to figure out how I can get the custom error message to be displayed instead. Any ideas?

.gitattributes to ignore differences between file endings

.gitattributes can be used to ignore different line endings in text.

This is useful for a text whose target audience are all (3) platforms, and who can be expected to contribute back from all (3) of those platforms.

The procedure, thanks to git's lovely standard behaviour of whateverworksforlinus, is a bit involved:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force Git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

But might be worth it.

Arity of operators

Last example in ch 7 [- (* 10 10) (+ 1 1 1)] should be malformed as it supplies 3 arguments to binary + operator. Current Grammar does not enforce the arity. Is this intentional?

Printing Expressions

Hello I am following the code in the book and in this chapter I am getting Segmentation fault: 11, I read on the internet that is caused by uninitialized access to data. I went through the code in the book few times and I can't spot the error. Could you check my code please?
This is the output from LLDB:

nbook:repl nohwnd$ lldb ./program 
(lldb) target create "./program"
Current executable set to './program' (x86_64).
(lldb) run
Process 5671 launched: './program' (x86_64)
Lispy Version
Press Ctrl+C to exit

lispy> + 2 2
Process 5671 stopped
* thread #1: tid = 0x34b02, 0x0000000100001164 program`lval_add + 20, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x20)
    frame #0: 0x0000000100001164 program`lval_add + 20
program`lval_add + 20:
-> 0x100001164:  movl   0x20(%rsi), %eax
   0x100001167:  addl   $0x1, %eax
   0x10000116c:  movl   %eax, 0x20(%rsi)
   0x10000116f:  movq   -0x8(%rbp), %rsi

The problem is likely in lval_read where NULL is assigned to x pointer. If I change that line to lval* x = lval_sexpr(); the code works correctly.

This is my full code:

#include "mpc.h"

/* if we compile on windows compile these functions */
#ifdef _WIN32
  #include <string.h>

  static char buffer[2048];

  /* fake readline function */
  char* readline (char* prompt) {
    fputs(prompt, stdout);
    fgets(buffer, 2048, stdin);
    char* cpy = malloc(strlen(buffer)+1);
    strcpy(cpy, buffer);
    cpy[strlen(cpy)-1] = '\0';

    return cpy;
  }

  /*fake history function*/
  void add_history(char*) {}
#else
  /*compiling on mac */
  #include <editline/readline.h>
#endif

typedef struct lval {
  int type;
  long num;
  /* Errors and Symbols have some string data */
  char* err;
  char* sym;

  int count;
  struct lval** cell;
} lval;

/* Possible lval types */
enum { LVAL_ERR, LVAL_NUM, LVAL_SYM, LVAL_SEXPR };

/* Possible error types */
enum { LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM };

/* Add lval as a child to SExpression */
lval* lval_add(lval* v, lval* x) {
  v->count++;
  v->cell = realloc(v->cell, sizeof(lval*) * v->count);
  v->cell[v->count-1] = x;

  return v;
}

/* Create pointer to new Number lval */
lval* lval_num(long x) {
  lval* v = malloc(sizeof(lval));
  v->type = LVAL_NUM;
  v->num = x;

  return v;
}

/* Create pointer to new Error val */
lval* lval_err(char* m) {
  lval* v = malloc(sizeof(lval));
  v->type = LVAL_ERR;
  v->err = malloc(strlen(m) + 1);
  strcpy(v->err, m);

  return v;
}

/* Create pointer to new Symbol lval */
lval* lval_sym(char* s) {
  lval* v = malloc(sizeof(lval));
  v->type = LVAL_SYM;
  v->sym = malloc(strlen(s) + 1);
  strcpy(v->sym, s);

  return v;
}

/* Create pointer to new empty SExpression lval */
lval* lval_sexpr(void) {
  lval* v = malloc(sizeof(lval));
  v->type = LVAL_SEXPR;
  v->count = 0;
  v->cell = NULL;

  return v;
}
/* Delete the lval and all it linked fields */
void lval_del(lval* v) {
  switch(v->type) {
    /* Do nothing special for number type */
    case LVAL_NUM:
      break;
    case LVAL_ERR:
      free(v->err);
      break;
    case LVAL_SYM:
      free(v->sym);
      break;
    case LVAL_SEXPR:
      for (int i = 0;  i < v->count; i++) {
        lval_del(v->cell[i]);
      }
      /* Free the memory allocated to hold the pointers as well */
      free(v->cell);
      break;
  }

  free(v);
}

lval* lval_read_num(mpc_ast_t* t) {
  errno = 0;
  long x = strtol(t->contents, NULL, 10);
  return errno != ERANGE ? lval_num(x) : lval_err("Invalid number");
}

lval* lval_read(mpc_ast_t* t) {
  /* If Symbol or Number return conversion to that type */
  if (strstr(t->tag, "number")) { return lval_read_num(t);}
  if (strstr(t->tag, "symbol")) { return lval_sym(t->contents); }
  /* If root (>) or sexpr then create empty list */
  lval* x = NULL;
  //lval* x = lval_sexpr();
  if(strstr(t->tag, ">") == 0) { x = lval_sexpr(); }
  if(strstr(t->tag, "sexpr")) { x = lval_sexpr(); }

  /* Fill this list with any valid expression contained within */
  for ( int i = 0; i < t->children_num; i++) {
    if (strcmp(t->children[i]->contents, "(") == 0 ) { continue; }
    if (strcmp(t->children[i]->contents, ")") == 0 ) { continue; }
    if (strcmp(t->children[i]->contents, "}") == 0 ) { continue; }
    if (strcmp(t->children[i]->contents, "{") == 0 ) { continue; }
    if (strcmp(t->children[i]->tag, "regex") == 0 ) { continue; }

    x = lval_add(x, lval_read(t->children[i]));
  }

  return x;
}

/* Forward define funciton that has circular reference */
void lval_expr_print(lval* v, char open, char close);

/* Print an lval */
void lval_print(lval* v) {
  switch (v->type) {
    /* In case the type is a number print it */
    /* Then break out of the switch */
    case LVAL_NUM:
      printf ("%li", v->num);
      break;

    /* In case the type is error find what error
    it is and print it */
    case LVAL_ERR:
      printf("Error: %s", v->err);
      break;
    case LVAL_SYM:
      printf("%s", v->sym);
      break;
    case LVAL_SEXPR:
      lval_expr_print(v,'(', ')');
      break;
  }
}

void lval_println(lval* v) {
  /* Print lval followed by new line */
  lval_print(v);
  putchar('\n');
}

void lval_expr_print(lval* v, char open, char close) {
  putchar(open);
  for (int i = 0; i < v->count; i++) {
    lval_print(v->cell[i]);

    /* Don't print trailing space if this is the last element */
    if (i != (v->count-1)) {
      putchar(' ');
    }
  }
  putchar(close);
}

int main (int argc, char** argv) {
  /* Create some parsers */
  mpc_parser_t* Number        = mpc_new("number");
  mpc_parser_t* Symbol        = mpc_new("symbol");
  mpc_parser_t* SExpression   = mpc_new("sexpression");
  mpc_parser_t* Expression    = mpc_new("expression");
  mpc_parser_t* Lispy         = mpc_new("lispy");

  /* Define the with the following language */
  mpca_lang(MPCA_LANG_DEFAULT,
  "number: /-?[0-9]+/; \
  symbol: '+'|'-'|'*'|'/'; \
  sexpression: '(' <expression>* ')'; \
  expression: <number> | <symbol> | <sexpression>; \
  lispy: /^/ <expression>* /$/;",
  Number, Symbol, SExpression, Expression, Lispy);


  /*Print Version and Exit information*/
  printf("Lispy Version\n");
  puts("Press Ctrl+C to exit\n");

  mpc_result_t r;

  /*In neverending loop */
  while(1){
    /*output our prompt and get input*/
    char* input = readline("lispy> ");
    /*Add input to history*/
    add_history(input);

    if (mpc_parse("<stdin>", input, Lispy, &r))
    {
      lval* x = lval_read(r.output);
      lval_println(x);
      lval_del(x);
    }
    else{
      /*Ohterwise print the error */
      mpc_err_print(r.error);
      mpc_err_delete(r.error);
    }

    free(input);
  }

  /* Undefine and delete the parsers */
  mpc_cleanup(4, Number, Symbol, SExpression, Expression, Lispy);
  return 0;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.