CS170

Project Assignment 1

TARGET DATE : Thursday 3/26.


Write a recursive descent parser for the subset of Scheme defined by the following EBNF grammar:

\(~~~~~~\)\(<\)s_expression\(>\) \(\longrightarrow\) ( { <s_expression> } ) | #t | #f | <symbol> | ()

where <symbol> is any string of non-whitespace characters that does not begin with "#", or "'" (the single quote), and that does not contain "(" or ")". In the grammar, terminals are in boldface, and all other symbols (e.g., the brackets { and }) are meta-linguistic symbols. The parsing of <symbol> will be handled by a lexical analyzer, which has already been written (see below for further information).

Your program should be capable of reading any number of Scheme s-expressions (as specified by the above syntax) and outputting the "parse tree" as represented by the appropriately indented recursive calls to the s_expression function, which you will write in C.

A sample output is given here. In the sample run, everything is program ouput, including the prompt "scheme>", except for the one-line lists (e.g., "(a b c)"), which are user input. Note that your program should continue to prompt for, accept, and parse user input until the user types ctrl-c. That mode of termination is not very elegant, of course. We'll take care of a more graceful exit in a later stage of the project.

The lexical analyzer is given in two files, lexer.h and lexer.c. The header file lexer.h provides sufficient documentation for using the code. To illustrate how it may be used, here is a file lextester.c that scans keyboard input, and an appropriate Makefile for compiling and linking the three (lexer.h, lexer.c, and lextester.c) and producing an executable named scheme. Note that the lexical analyzer returns the empty list "()" as if it were one token (this makes life easier for the parser). It also recognizes the single quote, but don't try having the parser deal with it at this point. It will be easier to handle the single quote later in the project.

Keep your code modular, now and for the remainder of this project. Separate the different functions of your project into natural units. For this assignment, it would make sense to create a file parser.h, containing the parser interface and another file parser.c for the parser implementation The interface file could be quite simple (HINT: "could" means "should" where simplicity is concerned!) at this point, e.g.,

    #ifndef PARSER
    #define PARSER
    #include <stdlib.h>

    void S_Expression ();

    #endif
All your main program would then have to do would be to #include parser.h, and call S_Expression() (inside a loop of course, as implied by the sample run). Hide as many details as you can from the client modules in general.

You may develop your project using any IDE (or none) according to taste. However, when the project is submitted, you must submit a zip file of a folder containing only the source files and a Makefile that will allow me to build the project using "make" at the command line on Linux. The executable must be named scheme as in the code you are given. This means you will almost certainly have to write your own Makefile different than the automatically generated one used by (say) Netbeans or Eclipse. Use the given Makefile as a model (which will be lightly adapted for this assignment). Your Makefile will undoubtedly be modified as the project progresses.

Submission location here.

Back to CS170 Assignments.