The executable should be testParser. Please add makefile. Please add as many comments as you can.
Verify the below Grammar is LL(1) or rewrite as needed in an equivalent form
Implement the parser in a separate file (parser.c and parser.h). Implement the main parser function in a separate file main.c: the main function should check for command line arguments, and then call the parser function to build the tree, and then implement recursive traversal to print the tree. Make sure it will check for the EOF token. The display is just for testing.
Implement the parser in two iterations:
1) Parser1.c : Starting without the parse tree. Have your parses generate error (print the line number and the nature of the problem such as token expected and token received) on the first error and exit, or print OK message upon successful parse.
2) For each non-terminal, use a void function named after the non-terminal. Decide how to pass the token. Be systematic: assume each function starts with unconsumed token (not matched yet) and returns unconsumed token. The non-LL(1) non-terminals with all-common prefix - implement the shortcut to mate them LL(1) rather than explicitly performing left-factorization
3) Parser2.c : Only after completing and testing the above to satisfaction, modify each parse function to build a subtree, and return its root node. Assume each function builds just the root and connects its subtrees. Modify the main function to receive the tree built in the parser, and then display it (for testing) using a preorder display. Add declaration file node.h
o do left to right traversal, for each new level use 2 space indentation
o when visiting a node print what the node is and what tokens it has if any, then print its children left to right the same way
o for every token, print token type, instance and line number
Some hints for tree:
- Every node should have a label consistent with the name of the function creating it.
- Every function creates exactly one tree node (or possibly none).
- The number of children seems as 3 max but it is your decision.
- All syntactic tokens such as () can be thrown away, all other tokens need to be stored in the tree.
- When storing a token, you may need to make a copy depending on your interface.
Grammar:
-> Start Stop
-> { }
-> empty | Var ID .
-> empty | : ID
-> Void() Return(ID);
-> empty |
-> + | - |
-> * |
-> / |
-> - |
-> () | ID | NUMBER
->
-> empty |
-> | | | | |
-> Read (ID) ;
-> Write () ;
-> Iff ( )
-> While ( )
-> ID == ;
-> =< | => | = | > | < | !
Example programs (assuming some standard semanticcs)
&short program prints 0
Start {
Write (0);
} Stop
&program echoes input*2
Start
Var x.
{ Read (x);
Write (2*x);
}
Stop
&print absolute value
Start {
Var x: y;
Read (x);
Iff (x<0) {
y == -x;
}
Write (y);
} Stop