Nodes of the abstract syntax tree.
Nodes of the abstract syntax tree.
The abstract syntax tree is one of the main data structures of the language implementation. It is produced by the parser and consumed by many of the other components (see overview).
The concrete nodes of the abstract syntax tree are implemented by case classes extending this trait, see “Known Subclasses” below for a list. They are further classified by nonterminal by intermediate traits in the inheritance hierarchy.
Nodes of the abstract syntax tree for expressions of the form “lhs +
rhs”.
Nodes of the abstract syntax tree for statements of the form “name =
value”.
Nodes of the abstract syntax tree for statements.
Builder for bytecode arrays.
Code generator.
A variant of the virtual machine that prints one line of debugging output for every instruction executed.
A variant of the virtual machine that prints one line of debugging output for every instruction executed.
To create a debug virtual machine, use the companion object’s apply methods.
Nodes of the abstract syntax tree for expressions.
Nodes of the abstract syntax tree for expressions.
The concrete nodes for expressions of the abstract syntax tree are implemented by case classes extending this trait, see “Known Subclasses” below for a list.
Nodes of the abstract syntax tree for statements of the form “if
(
condition )
thenBranch” or
“if
(
condition )
thenBranch else
elseBranch”.
Nodes of the abstract syntax tree for statements of the form “if
(
condition )
thenBranch” or
“if
(
condition )
thenBranch else
elseBranch”.
If there is no else
clause in the source code, the
elseBranch will be an empty Block as if “else {}
”
would have been in the source code.
Interpreter.
Turns a stream of characters into a stream of tokens.
Turns a stream of characters into a stream of tokens.
To create a lexer, use the companion object’s forFile
or forString
methods.
The lexer is the first main componenent in the language implementation. It reads a stream of characters from a file, or for testing, from a string. It produces a stream of tokens which is further processed by the parser.
The lexer classifies tokens according to their token type. The token type of the next token in the token stream is available from nextTokenType.
The lexer keeps track of line and column positions inside the source code. The first character of the source code is line 1 and column 1. The location of the beginning of the next token is available from startLine and startColumn. The location of the first character after the next token is available from currentLine and currentColumn.
Most token types classify a fixed string such as an operator or keyword. The following token types are special:
Nodes of the abstract syntax tree for expressions of the form “value”.
Nodes of the abstract syntax tree for expressions of the form “lhs *
rhs”.
Numbers at runtime.
Turns a stream of tokens into an abstract syntax tree.
Turns a stream of tokens into an abstract syntax tree.
To create a parser, use the companion object’s
forLexer
, forFile
,
or forString
methods.
The parser is the second main component in the language implementation. It reads a stream of tokens from the lexer. It produces an abstract syntax tree which is further processed by the other components (see overview).
The parser has one method parseN
for each nonterminal
symbol N
in the grammar´:
Additional parseN
methods are necessary for helper
nonterminal symbols to implement operator precedence:
Turns an abstract syntax tree back into a string.
Turns an abstract syntax tree back into a string.
To create a pretty printer, use the companion object’s
toPrintWriter
method.
The pretty printer is a helper component in the language implementation. It can be used during debugging to print out abstract syntax trees for manual inspection.
Nodes of the abstract syntax tree for statements of the form “print
(
value )
”.
Nodes of the abstract syntax tree for programs of the form “object
name extends
superclass {
body }
”.
Nodes of the abstract syntax tree for statements.
Nodes of the abstract syntax tree for statements.
The concrete nodes for statements of the abstract syntax tree are implemented by case classes extending this trait, see “Known Subclasses” below for a list.
Nodes of the abstract syntax tree for expressions of the form “lhs -
rhs”.
Mutable symbol table with support for nested scopes.
Used by the lexer to classify tokens in the token stream.
Used by the lexer to classify tokens in the token stream.
Each token type is implemented as a case object, see “Known Subclasses” below for a list.
Simple virtual machine, that is, bytecode interpreter.
Simple virtual machine, that is, bytecode interpreter.
To create a virtual machine, use the companion object’s apply methods.
For debugging, consider to use a debug virtual machine instead.
Values at runtime.
Values at runtime.
The representation of values of various dynamic types is implemented by case classes extending this trait, see “Known Subclasses” below for a list.
Nodes of the abstract syntax tree for statements of the form “var
name =
value”.
Nodes of the abstract syntax tree for expressions of the form “name”.
Nodes of the abstract syntax tree for statements of the form “while
(
condition )
body”.
Factory methods for Bytecode instances.
Used by the lexer to classify “}
” tokens in the token stream.
Used by the lexer to classify “)
” tokens in the token stream.
Factory methods for creating debug virtual machines.
Used by the lexer to classify “else
” tokens in the token stream.
Used by the lexer to classify the end of the token stream.
Used by the lexer to classify “=
” tokens in the token stream.
Used by the lexer to classify “extends
” tokens in the token stream.
Used by the lexer to classify identifier tokens in the token stream.
Used by the lexer to classify identifier tokens in the token stream.
The name of the identifier is available from Lexer.nextTokenText.
Used by the lexer to classify “if
” tokens in the token stream.
Used by the lexer to classify integer literal tokens in the token stream.
Used by the lexer to classify integer literal tokens in the token stream.
The value of the integer literal is available from Lexer.nextTokenIntegerValue.
Factory methods for creating lexers.
Used by the lexer to classify “-
” tokens in the token stream.
Used by the lexer to classify “object
” tokens in the token stream.
Opcodes of individual bytecode instructions.
Used by the lexer to classify “{
” tokens in the token stream.
Used by the lexer to classify “(
” tokens in the token stream.
Factory methods for creating parsers.
Used by the lexer to classify “+
” tokens in the token stream.
Factory methods for creating pretty printers.
Used by the lexer to classify “print
” tokens in the token stream.
Used by the lexer to classify “;
” tokens in the token stream.
Factory methods for creating symbol tables.
Used by the lexer to classify “*
” tokens in the token stream.
Factory methods for creating virtual machines.
Used by the lexer to classify “var
” tokens in the token stream.
Used by the lexer to classify “while
” tokens in the token stream.
An implementation of a small subset of Scala.
The code in this package is part of the course material for the course “Implementation of Programming Languages” at Tübingen University, Germany.
Main components:
Helper components:
Main data structures: