TC-1/2-Parser Code to Write
Warning
Be sure to read Bison documentations and tutorials, see RE/flex & Bison.
See the lecture notes, and read the C++ chapter of GNU Bison’s documentation.
Pay special attention to its ‘’Complete C++ Example’’ which is very much like our set up.
Take time to read all AST classes in The src/ast Directory directory to understand them well as you will build nodes in the parser and print them in the Pretty Printer.
What is to be done:
- Makefile.am
Include your own testsuite in the
testsdirectory. Some test examples are given in the tests folder (Given Test Cases). Do not hesitate to make use of them.Include your own test suite in the
testsdirectory, and hook it tomake check. See Generating The Test Driver.
- src/parse/tiger-factory.hxx
Implement all methods to create AST nodes on the driver with
make_methods.As mentioned above the
tiger-factoryfunctions will be used in Bison’s actions to create the different nodes of the AST.- src/parse/tasks.cc
Complete the
parseprocedure to setthe_program(the root of the AST) as the result of the parsing.- src/parse/parsetiger.yy
- Complete parser
The parser must be able to parse tokens as described in Syntactic Specifications and Additional Syntactic Specifications.
- What is Bison?
Bison is a parser generator, allowing to generate parsers of the LR family. Bison is a tool created by the GNU and maintained by Akim Demaille, the creator of the Tiger Compiler project (Fair Criticism). The goal of Bison is to write grammar rules in YACC (Yet another Compiler Compiler) format in order to be able to parse a language.
- What does Bison generate?
Bison generates two files:
parsetiger.hhandparsetiger.cc, which represent the parser. The parser is a class namedparse::parserwhich contains aparse(...)method to start parsing.- What is the structure of a Bison file?
A Bison file has a special syntax because it will generate C++. Here is a Bison Grammar Outline to the documentation for more information.
- How to write a Bison rule:
To write a rule with Bison you have to start from the EBNF grammar defined in the Syntactic Specifications and Additional Syntactic Specifications, then adapt it to the YACC syntax that Bison uses.
Here is an example of Bison code that parses this rule:
(* === Expressions. === *) exp = (* Literals. *) | INT | STRING ;
In Bison syntax:
exp: INT | STRING;
In this case
INTandSTRINGare tokens created by the lexer.During the development of your parser you will have problems with conflicts, there are two types of conflicts Shift/Reduce and Reduce/Reduce.
In order to solve these different problems, you are invited to read this documentation regarding the Bison algorithm.
For some cases such as function arguments, you will need to use recursive rules.
- GLR parser
We use
%glr-parserand%skeleton "glr2.cc"directives to have Bison generate a GLR parser. Thanks to GLR, some conflicts (S/R and/or R/R) can be resolved at runtime. Use%expectand%expect-rrto specify their number. For information, we allow zero R/R conflicts, and one S/R related to the “big lvalue” issue.- Trace the parsing
Use
%printerto implement--parse-tracesupport for terminals and non-terminals (see TC-1/2-Parser Samples).For instance,
%define api.value.type variant %token <int> INT "integer" %printer { yyo << $$; } <int>
You can also use the
PARSEenvironment variable to invoke parse tracing.
- Build the AST
To build your AST you will have to use Bison’s actions.
Here is an example of actions you can do for arithmetic operations:
/* Arithmetics. */ exp: /* this is the production rule */ exp "+" exp { $$ = $1 + $3; } | exp "=" exp { $$ = $1 == $3; } ...Statements between brackets are called actions. They allow to link the reduction of a rule to code. What we want to do is recursively build an AST. For that, we make use of action features.
We use the
$1action feature to retrieve the parsing production of the the first symbol (here, the left-hand sideexp).$3correspond to the third symbol (the right-hand sideexp);@$retrieves the location of the rule and$$means that the assigned expression will be the result of the production rule.The previous code example can also be written in this way:
/* Arithmetics. */ exp[result]: exp[left] "+" exp[right] { $result = $left + $right; } | exp[left] "=" exp[right] { $result = $left == $right; } ...The two version have the same behavior, but in this version we replaced the action features by named references. Here,
$$is replaced by$result,$1is replaced by$leftand$3is replaced by$right.To produce the AST you will have to use the same process but using this time the functions declared in the tiger-factory files.
/* example */ make_OpExp(/* insert the correct arguments */); make_IfExp(/* insert the correct arguments */);Warning
To have a full understanding of Bison’s actions read the Bison documentation about actions and action features.
- Desugar Boolean operators and unary minus in concrete syntax
In the original version of the exercise, the
|and&operators and the unary minus operator are desugared in abstract syntax (i.e., using explicit instantiations of AST nodes). Using TWEAST, you can desugar using Tiger’s concrete syntax instead. This second solution is advised.More information available in the syntactic sugar section on the
CCMPslides.- Support object-related syntax (Optional)
Supporting object constructs, an improvement suggested for TC-1/2 (see TC-1/2-Parser Improvements), is highly recommended.
- Error recovery (Optional)
There should be at least three uses of the error token. Read the Bison documentation about it. Use
%destructorto reclaim the memory bound to semantic values thrown away during error recovery.
- src/parse/tiger-driver.cc
The class
TigerDriverdrives the lexing and parsing of input file. Its implementation insrc/parse/tiger-driver.ccis incomplete.You have to add the creation of the lexer and the parser, as well as launch the parsing.
TigerDriveracts as a bridge between the lexer, the parser and the error handling, among other things. For more information, see old/02-parser-scanner.pdf: most of what you need to know is detailed here.
- src/ast/default-visitor.hxx
Complete the
GenDefaultVisitorclass template. It is the basis for following visitors in the Tiger compiler.For more information on the visitor design pattern, refactoring.guru may help you.
- src/ast/pretty-printer.*
The
PrettyPrinterclass must be written entirely. It must use themisc::indentfeatures to support indentation.- src/ast/object-visitor.hxx (Optional)
Likewise, complete
GenObjectVisitor. This class template is used to instantiate visitors factoring common code (default traversals of object-related nodes) and serves as a base class ofast::PrettyPrinter(and laterbind::Binder).- src/ast/dumper-dot.* (Optional)
The
DumperDotclass is used to create a graphviz dumper of your AST.The dumper dot, though not mandatory, is very useful for debugging as it allows to visualize its AST very simply. This part is optional an will not be tested (see TC-1/2-Parser Optional GraphViz Dumper).
An example of what the dumper
dotproduces:print-42.tiglet var life := 42 in print_int(life); print("\n") end
![digraph structs {
splines=line;
node [shape=plaintext]
902030976 [label=<
<table cellborder='0' cellspacing='0'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='nodename' colspan='1'>ChunkList</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902192768 [label=<
<table cellborder='0' cellspacing='0'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='nodename' colspan='1'>FunctionChunk</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902030976:nodename:s -> 902192768:nodename:n
902026624 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='red1'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>FunctionDec</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='name'>name: _main</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='formals'>formals</td>
<td port='result'>result</td>
<td port='body'>body</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902192768:nodename:s -> 902026624:nodename:n
902037168 [label=<
<table cellborder='0' cellspacing='0'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='nodename' colspan='1'>VarChunk</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902026624:formals:s -> 902037168:nodename:n
902027744 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>SeqExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='exps' colspan='2'>exps</td>
</tr>
<tr>
<td port='exps0'>0</td>
<td port='exps1'>1</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902026624:body:s -> 902027744:nodename:n
902114048 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>LetExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='chunks'>chunks</td>
<td port='body'>body</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902027744:exps0:s -> 902114048:nodename:n
902199856 [label=<
<table cellborder='0' cellspacing='0'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='nodename' colspan='1'>ChunkList</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902114048:chunks:s -> 902199856:nodename:n
902037072 [label=<
<table cellborder='0' cellspacing='0'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='nodename' colspan='1'>VarChunk</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902199856:nodename:s -> 902037072:nodename:n
902025552 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='red1'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>VarDec</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='name'>name: life</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='type_name'>type_name</td>
<td port='init'>init</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902037072:nodename:s -> 902025552:nodename:n
902039936 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>IntExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='value'>value: 42</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902025552:init:s -> 902039936:nodename:n
902035248 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>SeqExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='exps' colspan='2'>exps</td>
</tr>
<tr>
<td port='exps0'>0</td>
<td port='exps1'>1</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902114048:body:s -> 902035248:nodename:n
902200608 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>CallExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='name'>name: print_int</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='args' colspan='1'>args</td>
</tr>
</table>
</td>
<td port='def'>def</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902035248:exps0:s -> 902200608:nodename:n
902114176 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='orange1'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>SimpleVar</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='name'>name: life</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='def'>def</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902200608:args:s -> 902114176:nodename:n
902038144 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>CallExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='name'>name: print</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='args' colspan='1'>args</td>
</tr>
</table>
</td>
<td port='def'>def</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902035248:exps1:s -> 902038144:nodename:n
902026512 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>StringExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='value'>value: "\\n"</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902038144:args:s -> 902026512:nodename:n
902031600 [label=<
<table border='0' cellborder='0' cellspacing='0' cellpadding='0' color='blue2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td port='nodename'>SeqExp</td>
</tr>
</table>
</td>
</tr>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='1' cellspacing='0' cellpadding='2'>
<tr>
<td cellpadding='0'>
<table border='0' cellborder='0' cellspacing='0' cellpadding='0'>
<tr>
<td port='exps' colspan='1'>exps</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
>]
902027744:exps1:s -> 902031600:nodename:n
}](../../../_images/graphviz-719732de5f4c449c5d094ddfdf55bee3d71577c6.png)
print-42.png