Next: TC-2 Improvements, Previous: TC-2 Code to Write, Up: TC-2 [Contents][Index]
NameTy
, or a symbol
At some places, you may use one or the other. Just ask yourself which is the most appropriate given the context. Appel is not always right.
Be sure to read its dedicated section: Flex & Bison.
To reclaim the memory during error recovery, use the %destructor
directive:
%type <ast::Exp*> exp %type <ast::Var*> lvalue %destructor { delete $$; } <ast::Exp*> <ast::Var*> /* ... */;
See Valgrind, for a pointer to the explanation and solution.
misc::error
See misc/error, for a description of this component. In the case of
the parse module, TigerParser
aggregates the local error handler.
From scan_open
, for instance, your code should look like:
if(!yyin) error_ << misc::error::failure << program_name << ": cannot open `" << name << "': " << strerror(errno) << std::endl << &misc::error::exit;
ast::fields_type
vs. ast::VarDecs
The grammar of the Tiger language (see Syntactic Specifications in Tiger Compiler Reference Manual) includes:
# Function, primitive and method declarations. <dec> ::= "function" <id> "(" <tyfields> ")" [ ":" <type-id> ] "=" <exp> | "primitive" <id> "(" <tyfields> ")" [ ":" <type-id> ] <classfield> ::= "method" <id> "(" <tyfields> ")" [ ":" <type-id> ] "=" <exp> # Record type declaration. <ty> ::= "{" <tyfields> "}" # List of “id : type”. <tyfields> ::= [ <id> ":" <type-id> { "," <id> ":" <type-id> } ]
This grammar snippet shows that we used tyfields
several times,
in two very different contexts: a list of formal arguments of a
function, primitive or method; and a list of record fields. The fact
that the syntax is
similar in both cases is an “accident”: it is by no means required by
the language. A. Appel could have chosen to make them different, but
what would have been the point then? It does make sense, sometimes, to
make two different things look alike, that’s a form of economy — a
sane engineering principle.
If the concrete syntaxes were chosen to be identical, should it be the case for abstract too? We would say it depends: the inert data is definitely the same, but the behaviors (i.e., the handling in the various visitors) are very different. So if your language features “inert data”, say C or ML, then keeping the same abstract syntax makes sense; if your language features “active data” — let’s call this... objects — then it is a mistake. Sadly enough, the first edition of Red Tiger book made this mistake, and we also did it for years.
The second edition of the Tiger in Java introduces a dedicated
abstract syntax for formal arguments; we made a different choice: there
is little difference between formal arguments and local variables, so we
use a VarDecs
, which fits nicely with the semantics of chunks.
Regarding the abstract syntax of a record type declaration, we use a
list of Field
s (aka fields_type
).
Of course this means that you will have to duplicate your parsing
of the tyfields
non-terminal in your parser.
ast::DefaultVisitor
and ast::NonObjectVisitor
The existence of ast::NonObjectVisitor
is the result of a
reasonable compromise between (relative) safety and complexity.
The problem is: as object-aware programs are to be desugared into object-free ones, (a part of) our front-end infrastructure must support two kinds of traversals:
ast::PrettyPrinter
,
object::Binder
, object::TypeChecker
,
object::DesugarVisitor
.
bind::Binder
,
type::TypeChecker
, and all other AST visitors.
The first category has visit methods for all type of nodes of our (object-oriented) AST, so they raise no issue. On the other hand, the second category of visitors knows nothing about objects, and should either be unable to visit AST w/ objects (static solution) or raise an error if they encounter objects (dynamic solution).
Which led us to several solutions:
accept
methods) must be duplicated, too.
ast::NonObjectVisitor
. That is the solution we chose.
Solutions 2 and 3 let us provide a default visitor for ASTs without objects, but it’s harder to have a meaningful default visitor for ASTs with objects: indeed, concrete visitors on ASTs w/ objects inherit from their non-object counterparts, where methods visiting object nodes are already defined! (Though they abort at run time.)
We have found that having two visitors (ast::DefaultVisitor
and
ast::NonObjectVisitor
) to solve this problem was more elegant,
rather than merging both of them in ast::DefaultVisitor
. The
pros are that ast::DefaultVisitor
remains a default visitor; the
cons are that this visitor is now abstract, since object-related nodes
have no visit implementation. Therefore, we also introduced an
ast::ObjectVisitor
performing default visits of the remaining
node types; the combined inheritance of both ast::DefaultVisitor
and ast::ObjectVisitor
provides a complete default visitor.
Next: TC-2 Improvements, Previous: TC-2 Code to Write, Up: TC-2 [Contents][Index]