CS712/CS812
Project Phase 4
Fall 2017
Due Sunday December 10


Use your Go compiler to implement LL(1) grammar analysis in Go:

  1. (50 points) Read a grammar from stdin. The grammar will be listed one production per line. The first production is a production for the start symbol. Other than this restriction that the first production will be for the start symbol, the productions can appear in any order. In particular, the productions do not need to be grouped by left-hand-side symbol. Each production is given as a (single) space separated list of symbols. (Note: symbols can be longer than a single character.) The first symbol on the line is the left-hand-side symbol of the production. The symbols on the right-hand side, if any, are listed in order following the left-hand-side symbol. (Note that null rules will be given as having an empty right-hand side.) You may assume that there will be at most ten right-hand-side symbols. I will only test using grammars that are formatted correctly.

    The nonterminal symbols are the set of symbols that appear on the left-hand side of the productions.

    The terminal symbols are the set of symbols that appear in the right-hand-side of at least one production, but do not appear as the left-hand side of any production.

    Print a report to stderr. Start by printing a line containing only "Start Symbol", followed by a blank line, followed by a line containing the start symbol, followed by a blank line. Next print a line containing only "Nonterminals", followed by a blank line, followed by a line containing the nonterminals, in any order, separated by a (single) space, followed by a blank line. Next print a line containing only "Terminals", followed by a blank line, followed by a line containing the terminals, in any order, separated by a (single) space, followed by a blank line.

  2. (10 points) Add a display of the null-deriving nonterminals to the report. Print a line containing only "Null-Deriving Nonterminals", followed by a blank line, followed by a line containing the null-deriving nonterminals, in any order, separated by a single space. Finally, print a blank line.

  3. (10 points) Add a display of the First sets to the report. Print a line containing only "First Sets", followed by a blank line, followed by the First sets, given one per line, in any order. Each First set should be displayed by the nonterminal followed immediately by a colon and a space, followed by the members of the set, in any order, separated by a (single) space. Finally, print a blank line.

  4. (10 points) Add a display of the Follow sets to the report. Print a line containing only "Follow Sets", followed by a blank line, followed by the Follow sets, in any order, given one per line. Each Follow set should be displayed by the nonterminal followed immediately by a colon and a space, followed by the members of the set, in any order, separated by a (single) space. Finally, print a blank line.

  5. (10 points) Add a display of the Predict sets for the productions to the report. Print a line containing only "Predict Sets", followed by a blank line, followed by the Predict sets, in any order. Each Predict set should be displayed using three lines. The first line should contain the production, displayed as it was in the input. The second line should contain the members of the Predict Set for the production, in any order, separated by a (single) space. The third line should be blank.

  6. (10 points) If the grammar is LL(1), add a line containing only "The grammar is LL(1).". If the grammar is not LL(1), add a line containing only "The grammar is NOT LL(1).". Then print a blank line.

You should implement items in the above list in the order that they are listed.

A sample input grammar is available in ~cs712/public/tests/phase4/hw1.grm.

In order to allow reading from stdin, I recommend adding support for the Scanln function from the standard Go fmt package. You can treat this function as if it was a predefined function, but you should modify your parser to allow an import at the top of the file (import . "fmt"). (You do not need to implement the import, but you must be able to parse it.)

Here is Go code to show how the productions might be read:

package main;

import . "fmt"

func main() {
  var left string;
  var right1 string;
  var right2 string;
  var right3 string;
  var right4 string;
  var right5 string;
  var right6 string;
  var right7 string;
  var right8 string;
  var right9 string;
  var right10 string;
  var n int;
  n = getProduction(&left, &right1, &right2, &right3, &right4, &right5,
    &right6, &right7, &right8, &right9, &right10)
  for n > 0 {
    println(left, `->`, right1, right2, right3, right4, right5, right6,
      right7, right8, right9, right10);
    n = getProduction(&left, &right1, &right2, &right3, &right4, &right5,
      &right6, &right7, &right8, &right9, &right10)
  }
}

func getProduction(left, right1, right2, right3, right4, right5, right6,
  right7, right8, right9, right10 *string) int {
  *left = ``;
  *right1 = ``;
  *right2 = ``;
  *right3 = ``;
  *right4 = ``;
  *right5 = ``;
  *right6 = ``;
  *right7 = ``;
  *right8 = ``;
  *right9 = ``;
  *right10 = ``;
  Scanln(left, right1, right2, right3, right4, right5, right6, right7,
    right8, right9, right10);
  if len(*left) == 0 {
    return 0;
  }
  if len(*right1) == 0 {
    return 1;
  }
  if len(*right2) == 0 {
    return 2;
  }
  if len(*right3) == 0 {
    return 3;
  }
  if len(*right4) == 0 {
    return 4;
  }
  if len(*right5) == 0 {
    return 5;
  }
  if len(*right6) == 0 {
    return 6;
  }
  if len(*right7) == 0 {
    return 7;
  }
  if len(*right8) == 0 {
    return 8;
  }
  if len(*right9) == 0 {
    return 9;
  }
  if len(*right10) == 0 {
    return 10;
  }
  return 11;
}

Note that this code requires that you also implement the "len" built-in function for strings.

This is just a suggestion. If you can find an easier, standard Go way to read lines from stdin, go ahead and do it your way.

You can add other features to your Go system, but your Go program to do the grammar analysis must be able to be compiled by gccgo.

To get full credit, your code must be adequately documented and structured. If I can't easily read and understand your code, you may lose points. This includes both your compiler and your Go code for the LL(1) grammar analysis.

You must give me back the system in the same form that I gave it to you. I must be able to install it and run it in the exact same way as when it was delivered to you. I would also like you to keep the source code organized in the same directory hierarchy. If you fail to do this, a significant deduction will be made to your grade.

Note that there is a script, distribute.sh, in ugo/bin, which will generate a tar file for you. This tar file is what I require you to submit to me for grading.

Your Go code should be placed in a single file called "LL1.go".

To turn in this assignment, type:
~cs712/bin/submit phase4 ugo.tar LL1.go

Submissions can be checked by typing:
~cs712/bin/scheck phase4

The assignment is due on Sunday December 10. There is a grace period to 8am on Monday December 11 when no late penalty will be assigned. Submissions between 8am December 11 and 8am December 12 will have a late penalty of 10 points. Submissions between 8am December 12 and 8am December 13 will have a late penalty of 30 points. No program may be turned in after 8am on Wednesday December 13.

Remember: you are expected to do your own work on this assignment.


Last modified on November 29, 2017.

Comments and questions should be directed to pjh@cs.unh.edu