CSE 423 HW#3: a Parser

Due: Tuesday February 25 11:59pm.

Write or adapt a Kotlin(-subset) grammar. The recommended starting point is

You will have to produce it into a .y file that works with Bison, and use it to produce a syntax tree for input K0 source files.

To the extent that you modify the grammar, you are advised to ignore/allow any number of shift/reduce conflicts unless you have an example where they result in an error. Do not tolerate any reduce/reduce conflicts -- they generally require grammar changes such as refactoring common sequences within two or more production rules. Whichever grammar/parser you use, you are responsible for making it work for you and for any bugs.

Your parser should include at least the following:

If there is a syntax error, you should report the filename and line number. Your program's exit status should be 0 if there are no errors, and a nonzero number to indicate errors. For lexical errors, use the exit status 1. For syntax errors, the exit status should be 2.

If there are no errors, you should print a text representation of a syntax tree.

Suppose we have a tree structure that looks something like:

struct tree {
   int prodrule;
   char *symbolname;
   int nkids;
   struct tree *kids[9]; /* if nkids >0 */
   struct token *leaf;   /* if nkids == 0; might be null */
};

int treeprint(struct tree *t, int depth)
{
  int i;

  printf("%*s %s: %d\n", depth*2, " ", humanreadable(t), t->nkids);
  
  for(i=0; i<t->nkids; i++)
    treeprint(t->kids[i], depth+1);

}
If you write a function humanreadable(t) that returns a human readable string, either from the production rule # or the optional symbolname, you can get output that looks something like
program: 1
 function: 2
  function header: 3
   typedecl: 1
   functioname: 1
   parmlist: 3
    ....

For leaves, print out the integer code and the lexeme (yytext[]) for the token, if any.