Commit c7710191 authored by Erwan Auer's avatar Erwan Auer

assignments: added examples for TC2 for !12

Due to examples and files numerotations and files encoding,
there is a lot of modifications.

* compiler_stages/tc_1/code_to_write.rst,
* compiler_stages/tc_2/chunks.rst,
* compiler_stages/tc_2/error_recovery.rst,
* compiler_stages/tc_2/pretty_printing_samples.rst,
* compiler_stages/tc_3/samples.rst,
* compiler_stages/tc_4/options.rst,
* compiler_stages/tc_4/samples.rst,
* compiler_stages/tc_5/builtin_calls_samples.rst,
* compiler_stages/tc_5/goals.rst,
* compiler_stages/tc_5/optimizing_cascading_if.rst,
* compiler_stages/tc_5/primitive_samples.rst,
* compiler_stages/tc_5/samples_with_variables.rst,
* compiler_stages/tc_6/samples/canonicalization_samples.rst,
* compiler_stages/tc_6/samples/scheduling_samples.rst,
* compiler_stages/tc_7/samples.rst,
* compiler_stages/tc_8/faq.rst,
* compiler_stages/tc_8/samples.rst,
* compiler_stages/tc_9/samples.rst,
* compiler_stages/tc_a/samples.rst,
* compiler_stages/tc_b/samples.rst,
* compiler_stages/tc_d/samples.rst,
* compiler_stages/tc_e/samples.rst,
* compiler_stages/tc_i/samples.rst,
* compiler_stages/tc_l/faq.rst,
* compiler_stages/tc_l/samples.rst,
* compiler_stages/tc_o/samples.rst,
* compiler_stages/tc_r/samples.rst,
* compiler_stages/tc_x/samples.rst,
* compiler_stages/tc_y/faq.rst,
* compiler_stages/tc_y/samples.rst: here.

* compiler_stages/tc_2/hello-world.tig: Add
parent 48ffcdd0
Pipeline #6274 passed with stage
in 1 minute and 4 seconds
......@@ -70,7 +70,7 @@ Pay special attention to its ''`Complete C++ Example`_'' which is *very much* li
src/parse/parsetiger.yy
- The grammar must be complete but without actions.
- Use :code:`%printer` to implement :code:`--parse-trace` support for
terminals (see :ref:`TC-1 Samples`)
......
.. _TC-2 Chunks:
TC-2 Chunks
-----------
The type checking rules of Tiger, or rather its binding rules, justify the contrived parsing of declarations.
This is why this section uses :code:`-b/--bindings-compute`, implemented later (see :ref:`TC-3`).
In Tiger, to support recursive types and functions, continuous declarations of functions and continuous declarations
of types are considered "simultaneously". For instance in the following program, :code:`foo` and :code:`bar`
are visible in each other's scope, and therefore the following program is correct wrt type checking.
.. code::
let function foo() : int = bar()
function bar() : int = foo()
in
0
end
**File 4.13**: foo-bar.tig
.. code::
$ tc -b foo-bar.tig
**Example 4.17**: tc -b foo-bar.tig
In the following sample, because :code:`bar` is not declared in the same bunch of declarations, it is not visible
during the declaration of :code:`foo`. The program is invalid.
.. code::
let function foo() : int = bar()
var stop := 0
function bar() : int = foo()
in
0
end
**File 4.14**: foo-stop-bar.tig
.. code::
$ tc -b foo-stop-bar.tig
error->foo-stop-bar.tig:1.28-32: undeclared function: bar
=>4
**Example 4.18**: tc -b foo-stop-bar.tig
The same applies to types.
We shall name *chunk* a continuous series of type (or function) declaration.
A single name cannot be defined more than once in a chunk.
.. code::
let function foo() : int = 0
function bar() : int = 1
function foo() : int = 2
var stop := 0
function bar() : int = 3
in
0
end
**File 4.15**: fbfsb.tig
.. code::
$ tc -b fbfsb.tig
error->fbfsb.tig:3.5-28: redefinition: foo
error->fbfsb.tig:1.5-28: first definition
=>4
**Example 4.19**: tc -b fbfsb.tig
It behaves exactly as if chunks were part of embedded let in end, i.e., as if the previous program was syntactic
sugar for the following one (in fact, in 2006-tc used to desugar it that way).
.. code::
let
function foo() : int = 0
function bar() : int = 1
in
let
function foo() : int = 2
in
let
var stop := 0
in
let
function bar() : int = 3
in
0
end
end
end
end
**File 4.16**: fbfsb-desugared.tig
Given the type checking rules for variables, whose definitions cannot be recursive, chunks of variable declarations
are reduced to a single variable.
.. _TC-2 Chunks:
TC-2 Chunks
-----------
The type checking rules of Tiger, or rather its binding rules, justify the contrived parsing of declarations.
This is why this section uses :code:`-b/--bindings-compute`, implemented later (see :ref:`TC-3`).
In Tiger, to support recursive types and functions, continuous declarations of functions and continuous declarations
of types are considered "simultaneously". For instance in the following program, :code:`foo` and :code:`bar`
are visible in each other's scope, and therefore the following program is correct wrt type checking.
.. code::
let function foo() : int = bar()
function bar() : int = foo()
in
0
end
**File 4.14**: foo-bar.tig
.. code::
$ tc -b foo-bar.tig
**Example 4.18**: tc -b foo-bar.tig
In the following sample, because :code:`bar` is not declared in the same bunch of declarations, it is not visible
during the declaration of :code:`foo`. The program is invalid.
.. code::
let function foo() : int = bar()
var stop := 0
function bar() : int = foo()
in
0
end
**File 4.15**: foo-stop-bar.tig
.. code::
$ tc -b foo-stop-bar.tig
error->foo-stop-bar.tig:1.28-32: undeclared function: bar
=>4
**Example 4.19**: tc -b foo-stop-bar.tig
The same applies to types.
We shall name *chunk* a continuous series of type (or function) declaration.
A single name cannot be defined more than once in a chunk.
.. code::
let function foo() : int = 0
function bar() : int = 1
function foo() : int = 2
var stop := 0
function bar() : int = 3
in
0
end
**File 4.16**: fbfsb.tig
.. code::
$ tc -b fbfsb.tig
error->fbfsb.tig:3.5-28: redefinition: foo
error->fbfsb.tig:1.5-28: first definition
=>4
**Example 4.20**: tc -b fbfsb.tig
It behaves exactly as if chunks were part of embedded let in end, i.e., as if the previous program was syntactic
sugar for the following one (in fact, in 2006-tc used to desugar it that way).
.. code::
let
function foo() : int = 0
function bar() : int = 1
in
let
function foo() : int = 2
in
let
var stop := 0
in
let
function bar() : int = 3
in
0
end
end
end
end
**File 4.17**: fbfsb-desugared.tig
Given the type checking rules for variables, whose definitions cannot be recursive, chunks of variable declarations
are reduced to a single variable.
.. _TC-2 Error Recovery:
TC-2 Error Recovery
-------------------
Your parser must be robust to (some) syntactic errors. Observe that on the following input several parse errors are
reported, not merely the first one:
.. code::
(
1;
(2, 3);
(4, 5);
6
)
**File 4.17**: multiple-parse-errors.tig
.. code::
$ tc multiple-parse-errors.tig
error->multiple-parse-errors.tig:3.5: syntax error, unexpected ",", expecting ;
error->multiple-parse-errors.tig:4.5: syntax error, unexpected ",", expecting ;
=>3
**Example 4.20**: tc multiple-parse-errors.tig
Of course, the exit status still reveals the parse error. Error recovery must not break the rest of the compiler.
.. code::
$ tc -XA multiple-parse-errors.tig
error->multiple-parse-errors.tig:3.5: syntax error, unexpected ",", expecting ;
error->multiple-parse-errors.tig:4.5: syntax error, unexpected ",", expecting ;
/* == Abstract Syntax Tree. == */
function _main() =
(
(
1;
();
();
6
);
()
)
=>3
**Example 4.21**: tc -XA multiple-parse-errors.tig
.. _TC-2 Error Recovery:
TC-2 Error Recovery
-------------------
Your parser must be robust to (some) syntactic errors. Observe that on the following input several parse errors are
reported, not merely the first one:
.. code::
(
1;
(2, 3);
(4, 5);
6
)
**File 4.18**: multiple-parse-errors.tig
.. code::
$ tc multiple-parse-errors.tig
error->multiple-parse-errors.tig:3.5: syntax error, unexpected ",", expecting ;
error->multiple-parse-errors.tig:4.5: syntax error, unexpected ",", expecting ;
=>3
**Example 4.21**: tc multiple-parse-errors.tig
Of course, the exit status still reveals the parse error. Error recovery must not break the rest of the compiler.
.. code::
$ tc -XA multiple-parse-errors.tig
error->multiple-parse-errors.tig:3.5: syntax error, unexpected ",", expecting ;
error->multiple-parse-errors.tig:4.5: syntax error, unexpected ",", expecting ;
/* == Abstract Syntax Tree. == */
function _main() =
(
(
1;
();
();
6
);
()
)
=>3
**Example 4.22**: tc -XA multiple-parse-errors.tig
.. _TC-2 Pretty-Printing Samples:
TC-2 Pretty-Printing Samples
----------------------------
The parser builds abstract syntax trees that can be output by a pretty-printing module:
.. code::
/* Define a recursive function. */
let
/* Calculate n!. */
function fact (n : int) : int =
if n = 0
then 1
else n * fact (n - 1)
in
fact (10)
end
**File 4.8**: simple-fact.tig
.. code::
$ tc -XA simple-fact.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
let
function fact(n : int) : int =
(if (n = 0)
then 1
else (n * fact((n - 1))))
in
fact(10)
end;
()
)
**Example 4.10**: tc -XA simple-fact.tig
The pretty-printed output must be *valid* and *equivalent*.
Valid means that any Tiger compiler must be able to parse with success your output. Pay attention to the banners
such as ':code:`== Abstract...`': you should use comments: ':code:`/* == Abstract... */`'. Pay attention to
special characters too.
.. code::
print("\"\x45\x50ITA\"\n")
**File 4.9**: string-escapes.tig
.. code::
$ tc -XA string-escapes.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
print("\"EPITA\"\n");
()
)
**Example 4.11**: tc -XA string-escapes.tig
*Equivalent* means that, except for syntactic sugar, the output and the input are equal. Syntactic sugar refers
to '&', '|', unary '-', etc.
.. code::
1 = 1 & 2 = 2
**File 4.10**: 1s-and-2s.tig
.. code::
$ tc -XA 1s-and-2s.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
(if (1 = 1)
then ((2 = 2) <> 0)
else 0);
()
)
**Example 4.12**: tc -XA 1s-and-2s.tig
.. code::
$ tc -XA 1s-and-2s.tig > output.tig
**Example 4.13**: tc -XA 1s-and-2s.tig > output.tig
.. code::
$ tc -XA output.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
(if (1 = 1)
then ((2 = 2) <> 0)
else 0);
()
)
**Example 4.14**: tc -XA output.tig
Beware that :code:`for` loops are encoded using a :code:`ast::VarDec`: do not display the ':code:`var`':
.. code::
for i := 0 to 100 do
(print_int (i))
**File 4.11**: for-loop.tig
.. code::
$ tc -XA for-loop.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
(for i := 0 to 100 do
print_int(i));
()
)
**Example 4.15**: tc -XA for-loop.tig
Parentheses must not stack for free; you must even remove them as the following example demonstrates.
.. code::
((((((((((0))))))))))
**File 4.12**: parens.tig
.. code::
$ tc -XA parens.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
0;
()
)
**Example 4.16**: tc -XA parens.tig
This is not a pretty-printer trick: the ASTs of this program and that of '0' are exactly the same: a
single :code:`ast::IntExp`.
As a result, *anything output by 'tc -A' is equal to what 'tc -A | tc -XA -' displays!*
.. _TC-2 Pretty-Printing Samples:
TC-2 Pretty-Printing Samples
----------------------------
**WARNING**: The ASTs outputed below are generated with the "-X" option, to avoid
useless repetition.
**Do not forget to test your pretty-printer without the option.**
.. code::
print("Hello, World!")
**File 4.8**: hello-world.tig
.. command-output:: tc -A hello-world.tig
:shell:
:cwd: .
**Example 4.9**: tc -A hello-world.tig
.. command-output:: tc -XA hello-world.tig
:shell:
:cwd: .
**Example 4.10**: tc -XA hello-world.tig
The parser builds abstract syntax trees that can be output by a pretty-printing module:
.. code::
/* Define a recursive function. */
let
/* Calculate n!. */
function fact (n : int) : int =
if n = 0
then 1
else n * fact (n - 1)
in
fact (10)
end
**File 4.9**: simple-fact.tig
.. code::
$ tc -XA simple-fact.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
let
function fact(n : int) : int =
(if (n = 0)
then 1
else (n * fact((n - 1))))
in
fact(10)
end;
()
)
**Example 4.11**: tc -XA simple-fact.tig
The pretty-printed output must be *valid* and *equivalent*.
Valid means that any Tiger compiler must be able to parse with success your output. Pay attention to the banners
such as ':code:`== Abstract...`': you should use comments: ':code:`/* == Abstract... */`'. Pay attention to
special characters too.
.. code::
print("\"\x45\x50ITA\"\n")
**File 4.10**: string-escapes.tig
.. code::
$ tc -XA string-escapes.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
print("\"EPITA\"\n");
()
)
**Example 4.12**: tc -XA string-escapes.tig
*Equivalent* means that, except for syntactic sugar, the output and the input are equal. Syntactic sugar refers
to '&', '|', unary '-', etc.
.. code::
1 = 1 & 2 = 2
**File 4.11**: 1s-and-2s.tig
.. code::
$ tc -XA 1s-and-2s.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
(if (1 = 1)
then ((2 = 2) <> 0)
else 0);
()
)
**Example 4.13**: tc -XA 1s-and-2s.tig
.. code::
$ tc -XA 1s-and-2s.tig > output.tig
**Example 4.14**: tc -XA 1s-and-2s.tig > output.tig
.. code::
$ tc -XA output.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
(if (1 = 1)
then ((2 = 2) <> 0)
else 0);
()
)
**Example 4.15**: tc -XA output.tig
Beware that :code:`for` loops are encoded using a :code:`ast::VarDec`: do not display the ':code:`var`':
.. code::
for i := 0 to 100 do
(print_int (i))
**File 4.12**: for-loop.tig
.. code::
$ tc -XA for-loop.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
(for i := 0 to 100 do
print_int(i));
()
)
**Example 4.16**: tc -XA for-loop.tig
Parentheses must not stack for free; you must even remove them as the following example demonstrates.
.. code::
((((((((((0))))))))))
**File 4.13**: parens.tig
.. code::
$ tc -XA parens.tig
/* == Abstract Syntax Tree. == */
function _main() =
(
0;
()
)
**Example 4.17**: tc -XA parens.tig
This is not a pretty-printer trick: the ASTs of this program and that of '0' are exactly the same: a
single :code:`ast::IntExp`.
As a result, *anything output by 'tc -A' is equal to what 'tc -A | tc -XA -' displays!*
This diff is collapsed.
.. _TC-4 Options:
TC-4 Options
------------
These are features that you might want to implement in addition to the core features.
**type::Error**
One problem is that type error recovery can generate false errors. For instance our compiler usually considers that
the type for incorrect constructs is :code:`Int`, which can create cascades of errors:
.. code::
"666" = if 000 then 333 else "666"
**File 4.38**: is_devil.tig
.. code::
$ tc -T is_devil.tig
error->is_devil.tig:1.9-34: type mismatch
error-> then clause type: int
error-> else clause type: string
error->is_devil.tig:1.1-34: type mismatch
error-> left operand type: string
error-> right operand type: int
=>5
**Example 4.47**: tc -T is_devil.tig
One means to avoid this issue consists in introducing a new type, :code:`type::Error`, that the type checker
would never complain about. This can be a nice complement to :code:`ast::Error`.
**Various Desugaring**
See :ref:`TC-D`, for more details. This is quite an easy option, and a very interesting one. Note that implementing
desugaring makes TC-5 easier.
**Bounds Checking**
If you felt TC-D was easy, then implementing bounds checking should be easy too. See :ref:`TC-B`.
**Overloaded Tiger**
See :ref:`TC-A`, for a description of this ambitious option.
**Renaming object-oriented constructs**
Like TC-R, this task consists in writing a visitor renaming AST nodes holding names (either defined or used), this
time with support for object-oriented constructs (option :code:`--object-rename`). This visitor,
:code:`object::Renamer`, shall also update named types (:code:`type::Named`) and collect the names of all (renamed)
classes. This option is essentially a preliminary step of TC-O (see the next item).
**Desugaring Tiger to Panther**
If your compiler is complete w.r.t. object constructs (in particular, the type-checking and the renaming of objects
is a requirement), then you can implement this very ambitious option, whose goal is to convert a Tiger program with
object constructs into a program with none of them (i.e., in the subset of Tiger called *Panther*). This work
consists in completing the :code:`object::DesugarVisitor` and implementing the :code:`--object-desugar` option.