<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<!-- -*- xhtml -*- --> | |
<title>JavaCC Lexer Generator Integration Tutorial for the NetBeans Platform</title> | |
<link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css"/> | |
<meta name="AUDIENCE" content="NBUSER"/> | |
<meta name="TYPE" content="ARTICLE"/> | |
<meta name="EXPIRES" content="N"/> | |
<meta name="developer" content="gwielenga@netbeans.org"/> | |
<meta name="indexed" content="y"/> | |
<meta name="description" | |
content="A short guide to integrating JavaCC into the NetBeans Platform."/> | |
<!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. --> | |
<!-- Use is subject to license terms.--> | |
</head> | |
<body> | |
<h1>JavaCC Lexer Generator Integration Tutorial for the NetBeans Platform</h1> | |
<p>This tutorial shows you how to generate a lexer with <a href="http://javacc.java.net/">JavaCC</a> | |
and use it to create editor features for | |
applications created on top of the NetBeans Platform.</p> | |
<p><b class="notes">Note:</b> This document uses NetBeans IDE 7.2 or above and NetBeans Platform 7.2 or above. If you | |
are using an earlier version, see <a href="71/nbm-javacc-lexer.html">the previous version | |
of this document</a>.</p> | |
<p><b>Contents</b></p> | |
<p><img src="../images/articles/74/netbeans_stamp_74_73_72.png" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 7.2" title="Content on this page applies to NetBeans IDE 7.2"/></p> | |
<ul class="toc"> | |
<li><a href="#intro">Introduction</a></li> | |
<li><a href="#creating">Creating the Module</a></li> | |
<li><a href="#recognizing">Recognizing SJ Files</a></li> | |
<li><a href="#generating">Generating a Lexer from JavaCC</a></li> | |
<li><a href="#integrating">Integrating the JavaCC Lexer with NetBeans APIs</a></li> | |
<li><a href="#registering">Registering the NetBeans Lexer</a></li> | |
<li><a href="#enable">Enabling Lexer Support in NetBeans Platform Applications</a></li> | |
<li><a href="#defining">Defining Tokens and Assigning Colors</a></li> | |
</ul> | |
<p><b>To follow this tutorial, you need the software and resources listed in the following | |
table.</b></p> | |
<table> | |
<tbody> | |
<tr> | |
<th class="tblheader" scope="col">Software or Resource</th> | |
<th class="tblheader" scope="col">Version Required</th> | |
</tr> | |
<tr> | |
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td> | |
<td class="tbltd1">version 7.2 or above</td> | |
</tr> | |
<tr> | |
<td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">Java Developer Kit (JDK)</a></td> | |
<td class="tbltd1">version 7 or above</td> | |
</tr> | |
</tbody> | |
</table> | |
<p class="tips">For troubleshooting purposes, you are welcome to download the <a href="http://java.net/projects/nb-api-samples/sources/api-samples/show/versions/7.2/tutorials/SimpleJava">completed tutorial source code</a>.</p> | |
<p></p> | |
<p class="notes"><b>Note:</b> Though some explanations of JavaCC are given in this tutorial, | |
the focus here is not on JavaCC as such. This is NOT a JavaCC tutorial. | |
For background information and | |
a thorough understanding of JavaCC, see the related website, <a href="http://java.net/projects/javacc">http://java.net/projects/javacc</a>. | |
The intended | |
audience of this tutorial is the JavaCC user who would like to integrate a | |
generated JavaCC lexer into NetBeans IDE or into another application created atop the NetBeans Platform. In this tutorial, | |
JavaCC is discussed | |
only in so far as it is needed to set up a scenario for using the related | |
NetBeans APIs.</p> | |
<!-- | |
<p>A basic overview of the steps to be taken during the instructions | |
that follow can be seen here:</p> | |
<p><object><iframe width="560" height="315" src="http://www.youtube.com/embed/aOwdeoOlZ7E" frameborder="0" allowfullscreen></iframe></object></p>--> | |
<h2 class="tutorial"><a name="intro"></a>Introduction</h2> | |
<p>JavaCC is a generator for Java lexers and Java parsers. | |
A Java lexer and parser generator is a tool that reads a grammar | |
specification and converts it to a Java program that can recognize | |
matches to the grammar. </p> | |
<p>This tutorial focuses specifically on lexers. | |
Lexical analysis, or "lexing", is the process of | |
converting a sequence of characters into a sequence of tokens. | |
Functionality that performs lexical analysis is called a | |
lexical analyzer, a lexer, or a scanner. In this tutorial, | |
the term "lexer" will be used. A lexer typically | |
exists as a single function called by a parser. | |
For example, while a typical lexer recognizes parentheses as tokens, | |
it does nothing to ensure that an opening parentheses is matched | |
by a closing parentheses, which is a task for a parser. | |
</p> | |
<p class="tips"> Part 2 of this tutorial, the <a href="nbm-javacc-parser.html">JavaCC Parser Generator Integration Tutorial</a>, | |
shows you how to create a parser that parses the same text | |
that the lexer in this tutorial lexes.</p> | |
<p>The NetBeans Platform | |
provides hooks for integrating a lexer into your own Java desktop | |
application on the NetBeans Platform. For example, in this tutorial, | |
you use a sample grammar specification provided by JavaCC to generate a lexer and use | |
it to create syntax coloring | |
in an editor for a simplified | |
Java language defined by the sample grammar specification:</p> | |
<p><img style="border:1px solid black" src="../images/tutorials/javacc/72/result-1.png" alt="editor."/></p> | |
<p>The principles you learn in this tutorial should help you integrate | |
a JavaCC-based lexer of your own.</p> | |
<!-- ===================================================================================== --> | |
<h2 class="tutorial"><a name="creating"></a>Creating the Module</h2> | |
<p>In this section, we use a wizard to create the source structure that every NetBeans module requires. The | |
source structure consists of certain folders in specific places and a set of files that are | |
always needed. For example, every NetBeans module requires a <tt>nbproject</tt> folder, which holds | |
the project's metadata.</p> | |
<div class="indent"> | |
<ol> | |
<li>Choose File > New Project (Ctrl-Shift-N). Under Categories, select NetBeans Modules. Under Projects, | |
select Module. Click Next.</li> | |
<li><p>In the Name and Location panel, type <tt>SimpleJava</tt> in Project Name. | |
Change the | |
Project Location to any directory on your computer. Click Next.</p></li> | |
<li><p>In the Basic Module Configuration panel, type <tt>org.simplejava</tt> | |
as the Code Name Base. Click Finish.</p></li></ol> | |
</div> | |
<p> The IDE creates the <tt>SimpleJava</tt> | |
project:</p> | |
<p><img src="../images/tutorials/javacc/72/code-1.png" alt="source."/></p> | |
<p>The project contains all of your sources and | |
project metadata, such as the project's Ant build script. The project | |
opens in the IDE. You can view its logical structure in the Projects | |
window (Ctrl-1) and its | |
file structure in the Files window (Ctrl-2). </p> | |
<!-- ===================================================================================== --> | |
<h2><a name="recognizing"></a>Recognizing SJ Files</h2> | |
<p>In this section, we use a wizard to create the classes necessary for | |
recognizing "SimpleJava" files, for which we will create the | |
new "text/x-sj" MIME type, which will recognize files with | |
".sj" as their file extension.</p> | |
<p class="notes"><b>Note:</b> For details on the steps below, | |
follow the <a href="https://platform.netbeans.org/tutorials/nbm-filetype.html">File Type Integration Tutorial</a>.</p> | |
<div class="indent"> | |
<ol> | |
<li>Right-click the project node and | |
choose New > Other > Module Development > File Type.</li> | |
<li>In the File Recognition panel, do the following: | |
<br/> | |
<br/> | |
<ul> | |
<li>Type <tt>text/x-sj</tt> in the MIME Type edit box.</li> | |
<li>Type <tt>sj SJ</tt> in the by Filename Extension edit box.</li> | |
</ul> | |
<p>The File Recognition panel should now look as follows:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/code-2.png" alt="source."/></p> | |
<br/> | |
<p>Click Next.</p></li> | |
<li><p>In the Name and Location panel, type <tt>SJ</tt> as the Class Name Prefix | |
and browse to any 16x16 pixel image file as the new file type's icon, | |
as shown below.</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/code-3.png" alt="source."/></p> | |
<br/> | |
<p class="notes"><b>Note:</b> You can use any icon of a 16x16 pixel dimension. If you like, you can | |
right-click on this one and save it locally, and then | |
specify it in the wizard step above: | |
<img src="../images/tutorials/javacc/71/JavaIcon.gif" alt="gif."/></p> | |
</li> | |
<li><p>Click Finish. The Projects window should now look as follows:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/code-4.png" alt="source."/></p> | |
<br/> | |
<p class="tips">The newly generated files above are described in the <a href="https://platform.netbeans.org/tutorials/nbm-filetype.html">File Type Integration Tutorial</a>.</p> | |
</li> | |
<li><p>Right-click the module and choose Run. The application starts up, installing | |
your module. Make sure to create | |
a few files on disk with ".sj" as the file extension. The content of these | |
files is irrelevant at this stage. | |
In the application, once it has started up, go | |
to the Favorites window (Ctrl-3) and open a few | |
of the files that have ".sj" as their file extension.</p> | |
<p>You should see your icon is shown for the file type, the Actions | |
registered via the annotations in the <tt>DataObject</tt> are shown when you right-click | |
the file in the Favorites window, and three tabs are shown in | |
the editor (the source tab, the visual tab, and the local history tab):</p> | |
<br/> | |
<p><img style="border:1px solid black" src="../images/tutorials/javacc/72/code-5.png" alt="source."/></p> | |
<br/> | |
<p>Create a new Java project and then go to the New File dialog, where you should | |
see that your template has been registered:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/code-6.png" alt="source."/></p> | |
</li> | |
</ol> | |
</div> | |
<p>You now have a basic file type recognition infrastructure set up. In the next section, we generate | |
a lexer via JavaCC and then use it to add syntax coloring for the SJ file type.</p> | |
<!-- ======================================================================================= --> | |
<h2><a name="generating"></a>Generating a Lexer from JavaCC</h2> | |
<p>Let's now use JavaCC to generate a lexer!</p> | |
<div class="indent"> | |
<ol> | |
<li><p>Download "javacc-5.0.zip" from | |
<a href="http://java.net/projects/javacc/downloads">http://java.net/projects/javacc/downloads</a> | |
and unpack it to a folder somewhere. In this section, for purposes of this example, we | |
will use the grammar | |
specified in the <tt>Java1.5.jj</tt> file:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/javacc-1.png" alt="source."/></p> | |
<br/> | |
<p class="notes"><b>Note:</b> You can try to use a different version of JavaCC, but there could | |
be differences in the generated files, making the result | |
incompatible with the sections that follow. </p></li> | |
<li><p>Create a new package named <tt>org.simplejava.jcclexer</tt> in your project. | |
Copy the two files mentioned above, <tt>Java1.5.jj</tt> | |
and <tt>Token.java</tt>, into the | |
new package:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/javacc-2.png" alt="source."/></p> | |
<br/> | |
<p>In the next steps, we're going to tweak the <tt>Java1.5.jj</tt> file so that it fits our | |
specific needs.</p> | |
</li> | |
<li><p>Firstly, we need to make sure that the classes | |
that JavaCC will generate for us will be generated into the correct | |
package, that is, the package where we copied the two files above. | |
Add "package org.simplejava.jcclexer;" | |
to <tt>Java1.5.jj</tt> file after the "PARSER_BEGIN(JavaParser)" line, so | |
that the files will be generated in the correct package:</p> | |
<pre class="examplecode">PARSER_BEGIN(JavaParser) | |
<b>package org.simplejava.jcclexer;</b> | |
import java.io.*;</pre></li> | |
<li><p>The <tt>Java1.5.jj</tt> file contains the | |
descriptions of tokens for the Java parser. | |
That's nearly what we need for our own Java lexer, though | |
there are some differences. The lexer defined for the parser | |
hides some types of tokens, such as comments and whitespaces. | |
However, we need to see such tokens in the NetBeans lexer | |
because we want to define special colors for comments. | |
Therefore, we need to change that in our JavaCC file. </p> | |
<br/> | |
<ul><li><p>Change:</p> | |
<pre class="examplecode">SKIP : | |
{ | |
" " | |
| "\t" | |
| "\n" | |
| "\r" | |
| "\f" | |
}</pre> | |
to: | |
<pre class="examplecode">TOKEN : | |
{ | |
< WHITESPACE: | |
" " | |
| "\t" | |
| "\n" | |
| "\r" | |
| "\f"> | |
}</pre> | |
</li> | |
<li><p>For the same reason, change all SPECIAL_TOKEN definitions:</p> | |
<pre class="examplecode">SPECIAL_TOKEN : | |
{ | |
<SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")?> | |
} | |
<IN_FORMAL_COMMENT> | |
SPECIAL_TOKEN : | |
{ | |
<FORMAL_COMMENT: "*/" > : DEFAULT | |
} | |
<IN_MULTI_LINE_COMMENT> | |
SPECIAL_TOKEN : | |
{ | |
<MULTI_LINE_COMMENT: "*/" > : DEFAULT | |
}</pre> | |
<p>to TOKEN definitions:</p> | |
<pre class="examplecode">TOKEN : | |
{ | |
<SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")?> | |
} | |
<IN_FORMAL_COMMENT> | |
TOKEN : | |
{ | |
<FORMAL_COMMENT: "*/" > : DEFAULT | |
} | |
<IN_MULTI_LINE_COMMENT> | |
TOKEN : | |
{ | |
<MULTI_LINE_COMMENT: "*/" > : DEFAULT | |
}</pre> | |
</li> | |
<li>Delete this section, we will not need it in this tutorial: | |
<pre class="examplecode">/* >'s need special attention due to generics syntax. */ | |
TOKEN : | |
{ | |
< RUNSIGNEDSHIFT: ">>>" > | |
{ | |
matchedToken.kind = GT; | |
((MyToken)matchedToken).realKind = RUNSIGNEDSHIFT; | |
input_stream.backup(2); | |
matchedToken.image = ">"; | |
} | |
| < RSIGNEDSHIFT: ">>" > | |
{ | |
matchedToken.kind = GT; | |
((MyToken)matchedToken).realKind = RSIGNEDSHIFT; | |
input_stream.backup(1); | |
matchedToken.image = ">"; | |
} | |
| < GT: ">" > | |
}</pre> | |
</ul></li> | |
<li><p>Because we will use our <tt>Java1.5.jj</tt> grammar | |
file to create a lexer only, we can simplify it. | |
Add this line, which sets the BUILD_PARSER property to false:</p> | |
<pre class="examplecode">options { | |
JAVA_UNICODE_ESCAPE = true; | |
ERROR_REPORTING = false; | |
STATIC = false; | |
COMMON_TOKEN_ACTION = false; | |
TOKEN_FACTORY = "<b>Token</b>"; | |
JDK_VERSION = "1.5"; | |
<b>BUILD_PARSER = false;</b> | |
}</pre> | |
<p class="notes"><b>Note:</b> Also change <tt>MyToken</tt> to <tt>Token</tt>, as you can see above.</p> | |
</li> | |
<li><p>Part of the <tt>Java1.5.jj</tt> file is obsolete for our purposes, so let's delete some sections. | |
Firstly, keep the PARSER_BEGIN and PARSER_END | |
sections, but delete the JavaParser class body, so that you're | |
left with exactly this:</p> | |
<pre class="examplecode">PARSER_BEGIN(JavaParser) | |
package org.simplejava.jcclexer; | |
public class JavaParser {} | |
PARSER_END(JavaParser)</pre> | |
<p class="notes"><b>Note:</b> Though the parser start and end lines remain, the body of the | |
class should now be empty and have exactly the content shown above.</p> | |
<p>Also delete everything from these lines down to the end of the file:</p> | |
<pre class="examplecode">/***************************************** | |
* THE JAVA LANGUAGE GRAMMAR STARTS HERE * | |
*****************************************/</pre> | |
</li> | |
<li><p>The <tt>Java1.5.jj</tt> file is ready now and we can "compile" it | |
from the command line. Do so by starting in the directory | |
where the JavaCC file is found, then invoke the JavaCC executable, | |
passing in the file: | |
</p> | |
<pre class="examplecode">C:\tutorials\SimpleJava\src\org\simplejava\jcclexer>C:\javacc\javacc-5.0\bin\javacc Java1.5.jj</pre> | |
<p>On Unix systems:</p> | |
<pre class="examplecode">cd /tutorials/simplejava/src/org/simplejava/jcclexer /myjavacc/bin/javacc Java1.5.jj</pre> | |
<p>The command line should show the following:</p> | |
<pre>Java Compiler Compiler Version 5.0 (Parser Generator) | |
(type "javacc" with no arguments for help) | |
Reading from file Java1.5.jj . . . | |
File "TokenMgrError.java" does not exist. Will create one. | |
File "ParseException.java" does not exist. Will create one. | |
File "Token.java" does not exist. Will create one. | |
File "JavaCharStream.java" does not exist. Will create one. | |
Parser generated successfully.</pre> | |
<p>The result should be as follows:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/javacc-3.png" alt="source."/></p> | |
<br/> | |
<p class="notes"><b>Note:</b> As you can see, JavaCC has generated | |
several files, all of which should be compilable, that is, | |
there should be no red error marks in any of the generated files. | |
</p> | |
</li> | |
</ol> | |
</div> | |
<p>You've now completed the JavaCC part of the tutorial. | |
The time has come to use the generated files to create a new NetBeans Lexer plugin.</p> | |
<!-- ======================================================================================= --> | |
<h2><a name="integrating"></a>Integrating the JavaCC Lexer with NetBeans APIs</h2> | |
<p>In this section, we take the files generated in the previous section | |
and integrate them with the <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/overview-summary.html">NetBeans Lexer API</a>.</p> | |
<div class="indent"> | |
<ol> | |
<li><p>In the Projects window, right-click the Libraries node, and choose | |
Add Module Dependency, as shown below:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-1.png" alt="source."/></p> | |
<br/> | |
<p>Look for the "Lexer" module in the list:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-2.png" alt="source."/></p> | |
<br/> | |
<p>When you click OK, you should see the "Lexer" module is now | |
a dependency in your module:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-3.png" alt="source."/></p> | |
<br/> | |
</li> | |
<li><p>In your module, create a new package named <tt>org.simplejava.lexer</tt>.</p> | |
</li> | |
<li><p>The first class you need to implement is <tt><a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/org/netbeans/api/lexer/TokenId.html">org.netbeans.api.lexer.TokenId</a></tt>. | |
<tt>TokenId</tt> represents one type of token. | |
It has three properties:</p> | |
<ul> | |
<li><tt>name.</tt> Unique name of the token type, such as <tt>"KEYWORD_IF".</tt></li> | |
<li><tt>id.</tt> Unique number.</li> | |
<li><tt>primaryCategory.</tt> Used | |
for sharing a token coloring | |
among multiple token types.</li> | |
</ul> | |
<p>Create a class named <tt>SJTokenId</tt> and define it as follows:</p> | |
<pre class="examplecode">package org.simplejava.lexer; | |
import org.netbeans.api.lexer.TokenId; | |
public class SJTokenId implements TokenId { | |
private final String name; | |
private final String primaryCategory; | |
private final int id; | |
SJTokenId( | |
String name, | |
String primaryCategory, | |
int id) { | |
this.name = name; | |
this.primaryCategory = primaryCategory; | |
this.id = id; | |
} | |
@Override | |
public String primaryCategory() { | |
return primaryCategory; | |
} | |
@Override | |
public int ordinal() { | |
return id; | |
} | |
@Override | |
public String name() { | |
return name; | |
} | |
}</pre></li> | |
<li><p>The next class you need to implement is <tt><a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/org/netbeans/spi/lexer/LanguageHierarchy.html">org.netbeans.spi.lexer.LanguageHierarchy</a></tt>. | |
<tt>LanguageHierarchy</tt> provides a list of token types for our language and creates a new | |
instance of our lexer.</p> | |
<p>Create a class named <tt>SJLanguageHierarchy</tt> and define it as follows:</p> | |
<pre class="examplecode">package org.simplejava.lexer; | |
import java.util.*; | |
import org.netbeans.spi.lexer.LanguageHierarchy; | |
import org.netbeans.spi.lexer.Lexer; | |
import org.netbeans.spi.lexer.LexerRestartInfo; | |
public class SJLanguageHierarchy extends LanguageHierarchy<SJTokenId> { | |
private static List<SJTokenId> tokens; | |
private static Map<Integer, SJTokenId> idToToken; | |
private static void init() { | |
tokens = Arrays.<SJTokenId>asList(new SJTokenId[]{ | |
//[PENDING] | |
}); | |
idToToken = new HashMap<Integer, SJTokenId>(); | |
for (SJTokenId token : tokens) { | |
idToToken.put(token.ordinal(), token); | |
} | |
} | |
static synchronized SJTokenId getToken(int id) { | |
if (idToToken == null) { | |
init(); | |
} | |
return idToToken.get(id); | |
} | |
@Override | |
protected synchronized Collection<SJTokenId> createTokenIds() { | |
if (tokens == null) { | |
init(); | |
} | |
return tokens; | |
} | |
@Override | |
protected synchronized Lexer<SJTokenId> createLexer(LexerRestartInfo<SJTokenId> info) { | |
return new SJLexer(info); | |
} | |
@Override | |
protected String mimeType() { | |
return "text/x-sj"; | |
} | |
}</pre> | |
<p class="notes"><b>Note:</b> Because the <tt>SJLexer</tt> class does not | |
yet exist, a red error mark is shown in the NetBeans editor in the new | |
declaration for the non-existent <tt>SJLexer</tt> class. You will define | |
this class in the next step.</p> | |
</li> | |
<li><p>The last class you need to implement is <tt><a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/org/netbeans/spi/lexer/Lexer.html">org.netbeans.spi.lexer.Lexer</a></tt>. | |
<tt>Lexer</tt> reads input text and returns tokens for it. | |
In our case, the Lexer implementation needs to delegate | |
to the lexer generated by JavaCC.</p> | |
<p>Create a class named <tt>SJLexer</tt> and define it as follows:</p> | |
<pre class="examplecode">package org.simplejava.lexer; | |
import org.netbeans.spi.lexer.Lexer; | |
import org.netbeans.spi.lexer.LexerRestartInfo; | |
import org.simplejava.jcclexer.JavaCharStream; | |
import org.simplejava.jcclexer.JavaParserTokenManager; | |
import org.simplejava.jcclexer.Token; | |
class SJLexer implements Lexer<SJTokenId> { | |
private LexerRestartInfo<SJTokenId> info; | |
private JavaParserTokenManager javaParserTokenManager; | |
SJLexer(LexerRestartInfo<SJTokenId> info) { | |
this.info = info; | |
JavaCharStream stream = new JavaCharStream(info.input()); | |
javaParserTokenManager = new JavaParserTokenManager(stream); | |
} | |
@Override | |
public org.netbeans.api.lexer.Token<SJTokenId> nextToken() { | |
Token token = javaParserTokenManager.getNextToken(); | |
if (info.input().readLength() < 1) { | |
return null; | |
} | |
return info.tokenFactory().createToken(SJLanguageHierarchy.getToken(token.kind)); | |
} | |
@Override | |
public Object state() { | |
return null; | |
} | |
@Override | |
public void release() { | |
} | |
}</pre> | |
<p class="notes"><b>Note:</b> The class above does not compile at the moment | |
because <tt>JavaCharStream</tt> has not been defined to receive | |
a <tt>LexerInput</tt>. In the next step, we rewrite the | |
<tt>JavaCharStream</tt> class generated by JavaCC. | |
Our new version of <tt>JavaCharStream</tt>, listed in the next step, | |
reads input characters from <tt><a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/org/netbeans/spi/lexer/LexerInput.html">org.netbeans.spi.lexer.LexerInput</a></tt>, instead of the | |
standard <tt>InputStream</tt>.</p> | |
</li> | |
<li><p>Because we are now using | |
<tt>LexerInput</tt> instead of <tt>InputStream</tt>, another change | |
in <tt>JavaCharStream</tt> is needed because | |
the <tt>JavaParserTokenManager</tt> created by JavaCC is designed to | |
work with a <tt>java.io.Reader</tt> and recognizes a <EOF> | |
when the <tt>io.Reader</tt> throws an <tt>IOException</tt>. | |
However, though the <tt>LexerInput</tt> class logically corresponds to | |
<tt>java.io.Reader</tt>, its <tt>read()</tt> | |
method does not throw a checked exception. | |
Hence the <tt>BeginToken</tt> and the <tt>readChar</tt> methods below validate the | |
returned character and throw the exception, if necesary.</p> | |
<pre class="examplecode">package org.simplejava.jcclexer; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.Reader; | |
import java.io.UnsupportedEncodingException; | |
import org.netbeans.spi.lexer.LexerInput; | |
public class JavaCharStream { | |
private LexerInput input; | |
static boolean staticFlag; | |
public JavaCharStream(LexerInput input) { | |
this.input = input; | |
} | |
JavaCharStream(Reader stream, int i, int i0) { | |
throw new UnsupportedOperationException("Not yet implemented"); | |
} | |
JavaCharStream(InputStream stream, String encoding, int i, int i0) throws UnsupportedEncodingException { | |
throw new UnsupportedOperationException("Not yet implemented"); | |
} | |
char BeginToken() throws IOException { | |
return readChar(); | |
} | |
String GetImage() { | |
return input.readText().toString(); | |
} | |
public char[] GetSuffix(int len) { | |
if (len > input.readLength()) { | |
throw new IllegalArgumentException(); | |
} | |
return input.readText(input.readLength() - len, input.readLength()).toString().toCharArray(); | |
} | |
void ReInit(Reader stream, int i, int i0) { | |
throw new UnsupportedOperationException("Not yet implemented"); | |
} | |
void ReInit(InputStream stream, String encoding, int i, int i0) throws UnsupportedEncodingException { | |
throw new UnsupportedOperationException("Not yet implemented"); | |
} | |
void backup(int i) { | |
input.backup(i); | |
} | |
int getBeginColumn() { | |
return 0; | |
} | |
int getBeginLine() { | |
return 0; | |
} | |
int getEndColumn() { | |
return 0; | |
} | |
int getEndLine() { | |
return 0; | |
} | |
char readChar() throws IOException { | |
int result = input.read(); | |
if (result == LexerInput.EOF) { | |
throw new IOException("LexerInput EOF"); | |
} | |
return (char) result; | |
} | |
}</pre></li> | |
<li><p> After replacing the generated <tt>JavaCharStream</tt> with the | |
code in the previous step, everything should compile and your module structure | |
should be as follows:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-4.png" alt="source."/></p> | |
<br/> | |
</li> | |
</ol> | |
<p>You now have an implementation of the NetBeans Lexer API based | |
on a JavaCC lexer generated from a JavaCC grammar definition. In | |
the next section, you register your NetBeans lexer so that the | |
NetBeans Platform infrastructure can find it and load it | |
into the application.</p> | |
</div> | |
<!-- ======================================================================================= --> | |
<h2><a name="registering"></a>Registering the NetBeans Lexer</h2> | |
<p>You now have a NetBeans lexer. We need to register it so that it can be used.</p> | |
<div class="indent"> | |
<ol> | |
<li><p>In <tt>SJTokenId</tt>, define the following method, | |
which returns an instance of <tt>org.netbeans.api.lexer.Language</tt>:</p> | |
<pre class="examplecode">public static Language<SJTokenId> getLanguage() { | |
return new SJLanguageHierarchy().language(); | |
}</pre> | |
</li> | |
<li><p>The instance created statically above needs to be called from somewhere. | |
The call | |
is done from the <tt>layer.xml</tt> file, within the | |
<tt>CslPlugins</tt> | |
folder, where you register the class below as | |
a language instance, via the class annotation <tt>@LanguageRegistration</tt>:</p> | |
<pre class="examplecode">package org.simplejava; | |
import org.netbeans.api.lexer.Language; | |
import org.netbeans.modules.csl.spi.DefaultLanguageConfig; | |
import org.netbeans.modules.csl.spi.LanguageRegistration; | |
import org.simplejava.lexer.SJTokenId; | |
@LanguageRegistration(mimeType = "text/x-sj") | |
public class SJLanguage extends DefaultLanguageConfig { | |
@Override | |
public Language getLexerLanguage() { | |
return SJTokenId.getLanguage(); | |
} | |
@Override | |
public String getDisplayName() { | |
return "SJ"; | |
} | |
}</pre> | |
<p>For the class above to compile, you need a new dependency in your module:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-5.png" alt="source."/></p> | |
<br/> | |
<p class="tips"> When the module containing the above class is built, | |
the <tt>generated-layer.xml</tt> file in the module's 'build' folder, | |
which is visible in the Files window (Ctrl - 2), contains many new | |
entries, providing many default features for your language:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-6.png" alt="source."/></p> | |
<br/> | |
</li> | |
</ol> | |
</div> | |
<!-- ======================================================================================= --> | |
<h2><a name="enable"></a>Enabling Lexer Support in NetBeans Platform Applications</h2> | |
<p>In NetBeans IDE, lexer support is enabled via the "Lexer to NetBeans Bridge" module. This | |
module uses the <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-mimelookup/org/netbeans/api/editor/mimelookup/MimeLookup.html">MIME Lookup API</a> to search for language descriptions registered by modules | |
such as the one you are creating in this tutorial. If you are creating lexer support for | |
your own application created on the NetBeans Platform, you explictly need to add the enablement | |
module yourself, as explained below.</p> | |
<div class="indent"> | |
<ol> | |
<li>Right-click the application and choose Properties to open the | |
Project Properties dialog.</li> | |
<li>In the Libraries | |
tab of the Project Properties dialog, expand the "ide" cluster, | |
and select "Lexer to NetBeans Bridge". The code name base | |
for this module is <tt>org.netbeans.modules.lexer.nbbridge</tt>.</li> | |
</ol> | |
</div> | |
<p>Now your NetBeans Platform application will be able to find the lexer | |
support that you are creating in this tutorial.</p> | |
<!-- ======================================================================================= --> | |
<h2><a name="defining"></a>Defining Tokens and Assigning Colors</h2> | |
<p>Let's now work with the actual tokens that we're going to need. First, | |
we'll update the <tt>SJLanguageHierarchy</tt> with our tokens. After that, | |
we'll map the tokens to fonts and colors. Finally, we'll register our | |
new files in the virtual filesystem of the application we're working on.</p> | |
<div class="indent"> | |
<ol> | |
<li><p>Look in the generated <tt>JavaParserConstants</tt> file | |
and notice the tokens that have been generated by JavaCC.</p> | |
<pre class="examplecode"> | |
public interface JavaParserConstants { | |
int EOF = 0; | |
int WHITESPACE = 1; | |
int SINGLE_LINE_COMMENT = 4; | |
int FORMAL_COMMENT = 5; | |
int MULTI_LINE_COMMENT = 6; | |
int ABSTRACT = 8; | |
int ASSERT = 9; | |
int BOOLEAN = 10; | |
int BREAK = 11; | |
int BYTE = 12; | |
... | |
... | |
...</pre> | |
<p>Now tweak and then | |
copy the tokens above into your <tt>SJLanguageHierarchy</tt> file:</p> | |
<pre class="examplecode">tokens = Arrays.asList(new SJTokenId[]{ | |
new SJTokenId("EOF", "whitespace", 0), | |
new SJTokenId("WHITESPACE", "whitespace", 1), | |
new SJTokenId("SINGLE_LINE_COMMENT", "comment", 4), | |
new SJTokenId("FORMAL_COMMENT", "comment", 5), | |
new SJTokenId("MULTI_LINE_COMMENT", "comment", 6), | |
new SJTokenId("ABSTRACT", "keyword", 8), | |
new SJTokenId("ASSERT", "keyword", 9), | |
new SJTokenId("BOOLEAN", "keyword", 10), | |
new SJTokenId("BREAK", "keyword", 11), | |
new SJTokenId("BYTE", "keyword", 12), | |
... | |
... | |
...</pre> | |
<p class="tips">See the <a href="#appendix">Appendix</a> for the complete | |
list of tokens. Copy them from the appendix into your module.</p> | |
</li> | |
<li><p>Next, we need to map the categories to fonts and colors. This is | |
done declaratively, in an XML file, where we list the categories | |
and then declare the fonts and colors that should be applied. | |
In the main package | |
of the module, that is, <tt>org.simplejava</tt>, create a new XML file | |
named <tt>FontAndColors.xml</tt>, with the following content:</p> | |
<pre class="examplecode"><!DOCTYPE fontscolors PUBLIC | |
"-//NetBeans//DTD Editor Fonts and Colors settings 1.1//EN" | |
"https://netbeans.org/dtds/EditorFontsColors-1_1.dtd"> | |
<fontscolors> | |
<fontcolor name="character" default="char"/> | |
<fontcolor name="errors" default="error"/> | |
<fontcolor name="identifier" default="identifier"/> | |
<fontcolor name="keyword" default="keyword" foreColor="red"/> | |
<fontcolor name="literal" default="keyword" /> | |
<fontcolor name="comment" default="comment"/> | |
<fontcolor name="number" default="number"/> | |
<fontcolor name="operator" default="operator"/> | |
<fontcolor name="string" default="string"/> | |
<fontcolor name="separator" default="separator"/> | |
<fontcolor name="whitespace" default="whitespace"/> | |
<fontcolor name="method-declaration" default="method"> | |
<font style="bold" /> | |
</fontcolor> | |
</fontscolors></pre> | |
<p>This file defines how to visualize the tokens produced by the lexer. The <tt>fontcolor</tt> tag properties are as follows:</p> | |
<br/> | |
<ul> | |
<li>name: Name or primaryCategory of your token (or tokens).</li> | |
<li>default: Name of default coloring. All properties that are not defined | |
explicitly are inherited from this default coloring. Default coloring | |
is customizable in the Options window.</li> | |
<li>foreColor: Foreground color.</li> | |
<li>bgColor: Background color.</li> | |
<li>underline: Underlined color. Token will be underlined if specified.</li> | |
<li>strikeThrough: Strike through color.</li> | |
<li>waveUnderlined: Wave underlined color.</li> | |
</ul> | |
<p>The <tt>fontcolor</tt> tag can contain | |
a nested font tag. The <tt>font</tt> tag has | |
the following properties:</p> | |
<br/> | |
<ul> | |
<li>name: Name of font.</li> | |
<li>size: Font size.</li> | |
<li>style: Bold or italic style.</li> | |
</ul> | |
</li> | |
<li><p>Copy the following code into the <tt>SJTemplate.sj</tt> file. Not only will | |
you use the template file, that is, <tt>SJTemplate.sj</tt>, as | |
a template in the New File dialog, but also as example text to | |
be shown in the Options window, where the user will be able to | |
see the effect of their customized fonts and colors.</p> | |
<pre class="examplecode">/** | |
* SimpleJavadoc comment for <code>SimpleJavaExample</code> class. | |
* @author Simple Joe Smith | |
*/ | |
public class SimpleJavaExample { | |
@Deprecated public String method (int param) { | |
return "SimpleString " + '-' + 1.2; | |
}// line comment | |
}</pre> | |
</li> | |
<li><p>Add the following key/value pairs into the <tt>Bundle.properties</tt> | |
file of the main package, that is, the <tt>Bundle.properties</tt> file | |
found in <tt>org.simplejava</tt>:</p> | |
<pre class="examplecode">text/x-sj=Simple Java | |
character=Character | |
errors=Error | |
identifier=Identifier | |
keyword=Keyword | |
literal=Literal | |
comment=Comment | |
number=Number | |
operator=Operator | |
string=String | |
separator=Separator | |
whitespace=Whitespace | |
method-declaration=Method Declaration</pre> | |
<p>The above values will be shown in the Options window, in the panel | |
where the user will be able to change the predefined fonts | |
and colors per category.</p> | |
</li> | |
<li><p>Right-click the <tt>org.simplejava</tt> node, choose New | Other, | |
and then create a new layer file, from the category shown below:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-7.png" alt="source."/></p> | |
<br/> | |
<p>Click Next above and Finish. A new XML file is created and registered | |
in the manifest file of the module. The XML file defines the contributions | |
of the module to the virtual filesystem of the application of which it is a part.</p> | |
</li> | |
<li><p>Register the <tt>FontAndColors.xml</tt> file, as well as the | |
example file into the <tt>layer.xml</tt> file, by replacing the | |
default content of the file with the following:</p> | |
<pre class="examplecode"><?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "https://netbeans.org/dtds/filesystem-1_2.dtd"> | |
<filesystem> | |
<folder name="Editors"> | |
<folder name="text"> | |
<folder name="x-sj"> | |
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.simplejava.Bundle"/> | |
<folder name="FontsColors"> | |
<folder name="NetBeans"> | |
<folder name="Defaults"> | |
<file name="FontAndColors.xml" url="FontAndColors.xml"> | |
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.simplejava.Bundle"/> | |
</file> | |
</folder> | |
</folder> | |
</folder> | |
</folder> | |
</folder> | |
</folder> | |
<folder name="OptionsDialog"> | |
<folder name="PreviewExamples"> | |
<folder name="text"> | |
<file name="x-sj" url="SJTemplate.sj"/> | |
</folder> | |
</folder> | |
</folder> | |
</filesystem></pre> | |
</li> | |
<li><p>Check that your module now has this content:</p> | |
<br/> | |
<p><img src="../images/tutorials/javacc/72/add-lexer-9.png" alt="source."/></p> | |
<br/> | |
</li> | |
</ol> | |
<p>Run the module, open an SJ file, and you should see the correct coloring, | |
as defined in the files above:</p> | |
<p><img style="border:1px solid black" src="../images/tutorials/javacc/72/result-1.png" alt="editor."/></p> | |
<p>Look in the Options window, under the Tools menu, | |
and you should be able to change the fonts and colors for the file type.</p> | |
<p><img src="../images/tutorials/javacc/72/result-2.png" alt="editor."/></p> | |
</div> | |
<!-- ======================================================================================= --> | |
<p></p> | |
<div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&subject=Feedback:%20JavaCC%20Lexer%207.2%20Tutorial">Send Us Your Feedback</a></div> | |
<!-- ======================================================================================== --> | |
<h2><a name="nextsteps"></a>Next Steps</h2> | |
<p class="tips">This tutorial is the official version of | |
the first part of <a href="http://wiki.netbeans.org/How_to_create_support_for_a_new_language">http://wiki.netbeans.org/How_to_create_support_for_a_new_language</a>, | |
which, aside from being a rough draft, is partly | |
obsolete and out of date for the NetBeans Platform.</p> | |
<p class="tips"> Part 2 of this tutorial, the <a href="nbm-javacc-parser.html">JavaCC Parser Generator Integration Tutorial</a>, | |
shows you how to create a parser that parses the same text | |
that the lexer in this tutorial lexes.</p> | |
<p>For more information about creating and developing NetBeans modules, see the following resources: </p> | |
<ul> | |
<li><a href="https://platform.netbeans.org/index.html">NetBeans Platform Homepage</a></li> | |
<li><a href="https://netbeans.org/download/dev/javadoc/">NetBeans API List (Current Development Version)</a></li> | |
<li><a href="https://netbeans.org/kb/trails/platform.html">Other Related Tutorials</a></li> | |
</ul> | |
<!-- ======================================================================================== --> | |
<h2><a name="appendix"></a>Appendix</h2> | |
<p>The complete list of tokens, referred to in step 1 of the | |
section <a href="#defining">Defining Tokens and Assigning Colors</a> above, is as follows: </p> | |
<pre class="examplecode">tokens = Arrays.asList(new SJTokenId[]{ | |
new SJTokenId("EOF", "whitespace", 0), | |
new SJTokenId("WHITESPACE", "whitespace", 1), | |
new SJTokenId("SINGLE_LINE_COMMENT", "comment", 4), | |
new SJTokenId("FORMAL_COMMENT", "comment", 5), | |
new SJTokenId("MULTI_LINE_COMMENT", "comment", 6), | |
new SJTokenId("ABSTRACT", "keyword", 8), | |
new SJTokenId("ASSERT", "keyword", 9), | |
new SJTokenId("BOOLEAN", "keyword", 10), | |
new SJTokenId("BREAK", "keyword", 11), | |
new SJTokenId("BYTE", "keyword", 12), | |
new SJTokenId("CASE", "keyword", 13), | |
new SJTokenId("CATCH", "keyword", 14), | |
new SJTokenId("CHAR", "keyword", 15), | |
new SJTokenId("CLASS", "keyword", 16), | |
new SJTokenId("CONST", "keyword", 17), | |
new SJTokenId("CONTINUE", "keyword", 18), | |
new SJTokenId("_DEFAULT", "keyword", 19), | |
new SJTokenId("DO", "keyword", 20), | |
new SJTokenId("DOUBLE", "keyword", 21), | |
new SJTokenId("ELSE", "keyword", 22), | |
new SJTokenId("ENUM", "keyword", 23), | |
new SJTokenId("EXTENDS", "keyword", 24), | |
new SJTokenId("FALSE", "keyword", 25), | |
new SJTokenId("FINAL", "keyword", 26), | |
new SJTokenId("FINALLY", "keyword", 27), | |
new SJTokenId("FLOAT", "keyword", 28), | |
new SJTokenId("FOR", "keyword", 29), | |
new SJTokenId("GOTO", "keyword", 30), | |
new SJTokenId("IF", "keyword", 31), | |
new SJTokenId("IMPLEMENTS", "keyword", 32), | |
new SJTokenId("IMPORT", "keyword", 33), | |
new SJTokenId("INSTANCEOF", "keyword", 34), | |
new SJTokenId("INT", "keyword", 35), | |
new SJTokenId("INTERFACE", "keyword", 36), | |
new SJTokenId("LONG", "keyword", 37), | |
new SJTokenId("NATIVE", "keyword", 38), | |
new SJTokenId("NEW", "keyword", 39), | |
new SJTokenId("NULL", "keyword", 40), | |
new SJTokenId("PACKAGE", "keyword", 41), | |
new SJTokenId("PRIVATE", "keyword", 42), | |
new SJTokenId("PROTECTED", "keyword", 43), | |
new SJTokenId("PUBLIC", "keyword", 44), | |
new SJTokenId("RETURN", "keyword", 45), | |
new SJTokenId("SHORT", "keyword", 46), | |
new SJTokenId("STATIC", "keyword", 47), | |
new SJTokenId("STRICTFP", "keyword", 48), | |
new SJTokenId("SUPER", "keyword", 49), | |
new SJTokenId("SWITCH", "keyword", 50), | |
new SJTokenId("SYNCHRONIZED", "keyword", 51), | |
new SJTokenId("THIS", "keyword", 52), | |
new SJTokenId("THROW", "keyword", 53), | |
new SJTokenId("THROWS", "keyword", 54), | |
new SJTokenId("TRANSIENT", "keyword", 55), | |
new SJTokenId("TRUE", "keyword", 56), | |
new SJTokenId("TRY", "keyword", 57), | |
new SJTokenId("VOID", "keyword", 58), | |
new SJTokenId("VOLATILE", "keyword", 59), | |
new SJTokenId("WHILE", "keyword", 60), | |
new SJTokenId("INTEGER_LITERAL", "literal", 61), | |
new SJTokenId("DECIMAL_LITERAL", "literal", 62), | |
new SJTokenId("HEX_LITERAL", "literal", 63), | |
new SJTokenId("OCTAL_LITERAL", "literal", 64), | |
new SJTokenId("FLOATING_POINT_LITERAL", "literal", 65), | |
new SJTokenId("DECIMAL_FLOATING_POINT_LITERAL", "literal", 66), | |
new SJTokenId("DECIMAL_EXPONENT", "number", 67), | |
new SJTokenId("HEXADECIMAL_FLOATING_POINT_LITERAL", "literal", 68), | |
new SJTokenId("HEXADECIMAL_EXPONENT", "number", 69), | |
new SJTokenId("CHARACTER_LITERAL", "literal", 70), | |
new SJTokenId("STRING_LITERAL", "literal", 71), | |
new SJTokenId("IDENTIFIER", "identifier", 72), | |
new SJTokenId("LETTER", "literal", 73), | |
new SJTokenId("PART_LETTER", "literal", 74), | |
new SJTokenId("LPAREN", "operator", 75), | |
new SJTokenId("RPAREN", "operator", 76), | |
new SJTokenId("LBRACE", "operator", 77), | |
new SJTokenId("RBRACE", "operator", 78), | |
new SJTokenId("LBRACKET", "operator", 79), | |
new SJTokenId("RBRACKET", "operator", 80), | |
new SJTokenId("SEMICOLON", "operator", 81), | |
new SJTokenId("COMMA", "operator", 82), | |
new SJTokenId("DOT", "operator", 83), | |
new SJTokenId("AT", "operator", 84), | |
new SJTokenId("ASSIGN", "operator", 85), | |
new SJTokenId("LT", "operator", 86), | |
new SJTokenId("BANG", "operator", 87), | |
new SJTokenId("TILDE", "operator", 88), | |
new SJTokenId("HOOK", "operator", 89), | |
new SJTokenId("COLON", "operator", 90), | |
new SJTokenId("EQ", "operator", 91), | |
new SJTokenId("LE", "operator", 92), | |
new SJTokenId("GE", "operator", 93), | |
new SJTokenId("NE", "operator", 94), | |
new SJTokenId("SC_OR", "operator", 95), | |
new SJTokenId("SC_AND", "operator", 96), | |
new SJTokenId("INCR", "operator", 97), | |
new SJTokenId("DECR", "operator", 98), | |
new SJTokenId("PLUS", "operator", 99), | |
new SJTokenId("MINUS", "operator", 100), | |
new SJTokenId("STAR", "operator", 101), | |
new SJTokenId("SLASH", "operator", 102), | |
new SJTokenId("BIT_AND", "operator", 103), | |
new SJTokenId("BIT_OR", "operator", 104), | |
new SJTokenId("XOR", "operator", 105), | |
new SJTokenId("REM", "operator", 106), | |
new SJTokenId("LSHIFT", "operator", 107), | |
new SJTokenId("PLUSASSIGN", "operator", 108), | |
new SJTokenId("MINUSASSIGN", "operator", 109), | |
new SJTokenId("STARASSIGN", "operator", 110), | |
new SJTokenId("SLASHASSIGN", "operator", 111), | |
new SJTokenId("ANDASSIGN", "operator", 112), | |
new SJTokenId("ORASSIGN", "operator", 113), | |
new SJTokenId("XORASSIGN", "operator", 114), | |
new SJTokenId("REMASSIGN", "operator", 115), | |
new SJTokenId("LSHIFTASSIGN", "operator", 116), | |
new SJTokenId("RSIGNEDSHIFTASSIGN", "operator", 117), | |
new SJTokenId("RUNSIGNEDSHIFTASSIGN", "operator", 118), | |
new SJTokenId("ELLIPSIS", "operator", 119), | |
new SJTokenId("RUNSIGNEDSHIFT", "operator", 120), | |
new SJTokenId("RSIGNEDSHIFT", "operator", 121), | |
new SJTokenId("GT", "operator", 122) | |
});</pre> | |
<!-- ======================================================================================== --> | |
<!--<h2><a name="version"></a>Versioning </h2> | |
<table width="76%" > | |
<tbody> | |
<tr> | |
<td> | |
<b>Version</b> | |
</td> | |
<td> | |
<b>Date</b> | |
</td> | |
<td> | |
<b>Changes</b> | |
</td> | |
</tr> | |
<tr> | |
<td> | |
1 | |
</td> | |
<td> | |
3 January 2012 | |
</td> | |
<td> | |
<ul><li>Initial version.</li> | |
<li>To do: | |
<ul> | |
<li></li> | |
<li></li> | |
<li></li> | |
<li></li> | |
<li></li> | |
</ul> | |
</li> | |
</ul> | |
</td> | |
</tr> | |
</tbody> | |
</table>--> | |
</body> | |
</html> |