feature: the ternary operator. Therefore,
we can just modify the parser so it generates a ternary operator AST node. We
can then rely on the translation phase
to recognize this node and translate it
to correct Java bytecode without providing our own translation implementation
(this process is called AST translation).
Let’s begin with the first step, the lexer
modification.
Lexer modification. First, let’s add the
Elvis operator so it is recognized as a new token. We do
this by modifying the com.sun
. tools.javac.parser. Token class,
inserting the Elvis operator
as a new token value. See
Listing 1.
All the tokens are auto-
matically added to a keyword
table, which is defined in the
com.sun.to
ols.javac.parser
.Keywords class. The Keywords
class maps all token names
(the value passed into the
Token constructor) to their
Token instance.
The keyword table is then
used by the Java lexer to map
an input stream of characters
into a token sequence. The
lexer interface is specified in
com.sun.to
ols.javac.parser.Lexer and it
contains various methods, such as the
following:
■ ■ pos(), which returns the current position of the lexer
■ ■ next Token(), which reads the next
token
■ ■ token(), which returns the current
token, typically using the default
implementation that lies in com.sun
. tools.javac.parser.Scanner
public enum Token implements Formattable {
EOF,
ERROR,
...
QUES("?"),
ELVIS("?:"), // <---
COLON(":"),
...
}
com.sun.to
ols.javac.parser.Token
COMMUNITY
JAVA IN ACTION
The OpenJDK is
now the heart
of a vital piece
of technology
that (in application
software terms)
runs large parts
of our entire
civilization,
affecting billions
of people daily.
ABOUT US
Download all listings in this issue as text
between assignment expressions and
other types of expressions. For example,
x = 1 and x /= 5 are assignment expressions; x++ counts as another expression.
If term() discovers an assignment
operator in the expression, it parses the
left-hand side and the right-hand side
of the assignment separately by first
calling term1() and then termRest(); of
course, both of the sides can be made
of subexpressions. For all other kinds of
expressions, all the parsing is delegated
to term1(), which we’ll look at more
closely now.