mirror of
https://github.com/twiglet/cs2j.git
synced 2025-01-18 13:15:17 +01:00
Add a comment to the head of every Java output file stating that this file was produced by CS2J. A command line argument (markDate) controls whether the translation date is included in this initial comment. markDate should be set false for Rustici (end similar) else it will produce spurious source control diffs
812 lines
24 KiB
Plaintext
812 lines
24 KiB
Plaintext
header {
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Xml;
|
|
using TokenStreamHiddenTokenFilter = antlr.TokenStreamHiddenTokenFilter;
|
|
}
|
|
|
|
options {
|
|
language = "CSharp";
|
|
namespace = "RusticiSoftware.Translator";
|
|
}
|
|
|
|
/** Java 1.3 AST Pretty Printer
|
|
*
|
|
* Author: Kevin Glynn <kevin.glynn@scorm.com>
|
|
*
|
|
* This grammar is based on the java tree walker included in ANTLR examples
|
|
*
|
|
*/
|
|
|
|
class JavaPrettyPrinter extends TreeParser("RusticiSoftware.Translator.JavaTreeParser");
|
|
|
|
options {
|
|
importVocab = CSharpJava;
|
|
buildAST = false;
|
|
}
|
|
|
|
{
|
|
|
|
private int indentLevel = 0;
|
|
private const string INDENT = " ";
|
|
private bool indented = false;
|
|
private bool doIndent = true;
|
|
private const int MAX_TOKEN_TYPE=350; // imprecise but big enough
|
|
private TokenStreamHiddenTokenFilter filter;
|
|
private XmlTextWriter enumXmlWriter;
|
|
private ArrayList enumMembers = new ArrayList();
|
|
|
|
private bool inClassModifiers = false; // Filter out static, this isn't the right place but pending rewrite this is quickest.
|
|
|
|
/** walk list of hidden tokens in order, printing them out */
|
|
public void dumpHidden(TextWriter w, antlr.IHiddenStreamToken t) {
|
|
for ( ; t!=null ; t=filter.getHiddenAfter(t) ) {
|
|
w.Write(t.getText());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prints the text of the specified AST node
|
|
/// </summary>
|
|
/// <param name="w">The output destination.</param>
|
|
/// <param name="node">The AST node to print.</param>
|
|
private void Print(TextWriter w, AST node)
|
|
{
|
|
Print(w, node, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prints the text
|
|
/// </summary>
|
|
/// <param name="w">The output destination.</param>
|
|
/// <param name="node">The AST node to print.</param>
|
|
private void Print(TextWriter w, string text)
|
|
{
|
|
Print(w, null, text);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Prints the text of the AST node if it exists, then the text if it exists
|
|
/// </summary>
|
|
/// <param name="w">The output destination.</param>
|
|
/// <param name="node">The AST node to print.</param>
|
|
private void Print(TextWriter w, AST node, string text)
|
|
{
|
|
if (doIndent && !indented) {
|
|
PrintIndent(w);
|
|
}
|
|
if (node != null)
|
|
{
|
|
w.Write(node.getText());
|
|
}
|
|
if (text != null)
|
|
{
|
|
w.Write(text);
|
|
}
|
|
if (node != null)
|
|
{
|
|
// disable for now
|
|
// dumpHidden(w, ((antlr.CommonASTWithHiddenTokens)node).getHiddenAfter());
|
|
}
|
|
}
|
|
|
|
private void PrintNL(TextWriter w)
|
|
{
|
|
w.Write("\n"); // Should we be switching to use Environment.NewLine?
|
|
//w.Write(Environment.NewLine);
|
|
if (doIndent) indented = false;
|
|
}
|
|
|
|
private void PrintNLIfReq(TextWriter w)
|
|
{
|
|
if (doIndent && indented)
|
|
PrintNL(w);
|
|
}
|
|
|
|
|
|
private void PrintIndent(TextWriter w)
|
|
{
|
|
for (int i = 0; i < indentLevel; i++) {
|
|
w.Write(INDENT);
|
|
}
|
|
if (doIndent) indented = true;
|
|
}
|
|
|
|
private void WriteStartEnum(AST node)
|
|
{
|
|
if (enumXmlWriter != null)
|
|
{
|
|
enumXmlWriter.WriteStartElement("enum");
|
|
enumXmlWriter.WriteAttributeString("id", node.getText());
|
|
}
|
|
}
|
|
|
|
private void WriteEndEnum()
|
|
{
|
|
if (enumXmlWriter != null)
|
|
{
|
|
enumXmlWriter.WriteEndElement();
|
|
}
|
|
}
|
|
|
|
private void WriteEnumMembers()
|
|
{
|
|
if (enumXmlWriter != null)
|
|
{
|
|
int num = 0;
|
|
foreach (AST node in enumMembers)
|
|
{
|
|
enumXmlWriter.WriteStartElement("member");
|
|
enumXmlWriter.WriteAttributeString("id", node.getText());
|
|
enumXmlWriter.WriteAttributeString("value", num.ToString());
|
|
enumXmlWriter.WriteEndElement();
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prints standard text at the top of each output file
|
|
/// </summary>
|
|
/// <param name="w">The output destination.</param>
|
|
/// <param name="emitDate">Emit Translation Date as part of prelude.</param>
|
|
private void PrintFilePrelude(TextWriter w, Boolean emitDate)
|
|
{
|
|
String stdPrelude = @"
|
|
//
|
|
//
|
|
// This file was translated from C# to Java by CS2J (http://www.cs2j.com).
|
|
//
|
|
// This code is to be used for evaluation of the CS2J tool ONLY.
|
|
//
|
|
// For more information about CS2J please contact cs2jcontact@scorm.com
|
|
//
|
|
";
|
|
|
|
if (emitDate) {
|
|
//stdPrelude += "// Translated: " + DateTime.Now.ToString("s") + Environment.NewLine +
|
|
// "//" + Environment.NewLine;
|
|
|
|
stdPrelude += "// Translated: " + DateTime.Now.ToString("s") + "\n//\n" ; // Switch to Environment.NewLine??
|
|
}
|
|
stdPrelude += "\n";
|
|
w.Write(stdPrelude);
|
|
}
|
|
|
|
|
|
// keving: Found this precedence table on the ANTLR site.
|
|
|
|
/** Encodes precedence of various operators; indexed by token type.
|
|
* If precedence[op1] > precedence[op2] then op1 should happen
|
|
* before op2;
|
|
*/
|
|
private static int[] precedence = new int[MAX_TOKEN_TYPE];
|
|
|
|
static JavaPrettyPrinter()
|
|
{
|
|
for (int i=0; i<precedence.Length; i++) {
|
|
// anything but these operators binds super tight
|
|
// for example METHOD_CALL binds tighter than PLUS
|
|
precedence[i] = int.MaxValue;
|
|
}
|
|
precedence[ASSIGN] = 1;
|
|
precedence[PLUS_ASSIGN] = 1;
|
|
precedence[MINUS_ASSIGN] = 1;
|
|
precedence[STAR_ASSIGN] = 1;
|
|
precedence[DIV_ASSIGN] = 1;
|
|
precedence[MOD_ASSIGN] = 1;
|
|
precedence[SHIFTR_ASSIGN] = 1;
|
|
//precedence[BSR_ASSIGN] = 1;
|
|
precedence[SHIFTL_ASSIGN] = 1;
|
|
precedence[BIN_AND_ASSIGN] =1;
|
|
precedence[BIN_XOR_ASSIGN] = 1;
|
|
precedence[BIN_OR_ASSIGN] = 1;
|
|
|
|
precedence[QUESTION] = 2;
|
|
|
|
precedence[LOG_OR] = 3;
|
|
|
|
precedence[LOG_AND] = 4;
|
|
|
|
precedence[BIN_OR] = 5;
|
|
|
|
precedence[BIN_XOR] = 6;
|
|
|
|
precedence[BIN_AND] = 7;
|
|
|
|
precedence[NOT_EQUAL] = 8;
|
|
precedence[EQUAL] = 8;
|
|
|
|
precedence[LTHAN] = 9;
|
|
precedence[GTHAN] = 9;
|
|
precedence[LTE] = 9;
|
|
precedence[GTE] = 9;
|
|
precedence[INSTANCEOF] = 9;
|
|
|
|
precedence[SHIFTL] = 10;
|
|
precedence[SHIFTR] = 10;
|
|
//precedence[BSR] = 10;
|
|
|
|
precedence[PLUS] = 11;
|
|
precedence[MINUS] = 11;
|
|
|
|
precedence[DIV] = 12;
|
|
precedence[MOD] = 12;
|
|
precedence[STAR] = 12;
|
|
|
|
precedence[INC] = 13;
|
|
precedence[DEC] = 13;
|
|
precedence[BIN_NOT] = 13;
|
|
precedence[LOG_NOT] = 13;
|
|
precedence[UNARY_MINUS] = 13;
|
|
precedence[UNARY_PLUS] = 13;
|
|
|
|
precedence[POST_INC_EXPR] = 14;
|
|
precedence[POST_DEC_EXPR] = 14;
|
|
}
|
|
|
|
|
|
// Compares precedence of op1 and op2.
|
|
// Returns -1 if op2 < op1
|
|
// 0 if op1 == op2
|
|
// 1 if op2 > op1
|
|
public static int comparePrecedence(AST op1, AST op2) {
|
|
// A gross hack for "instanceof" (no longer necessary with C# front end :-))
|
|
// if (op1.getText() == "instanceof")
|
|
// precedence[op1.Type] = 9;
|
|
// if (op2.getText() == "instanceof")
|
|
// precedence[op2.Type] = 9;
|
|
|
|
return Math.Sign(precedence[op2.Type]-precedence[op1.Type]);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
compilationUnit [TextWriter w, XmlTextWriter enumXmlWriter, TokenStreamHiddenTokenFilter f, Boolean emitDate]
|
|
{ filter = f; this.enumXmlWriter = enumXmlWriter; PrintFilePrelude(w, emitDate); }
|
|
: #( COMPILATION_UNIT
|
|
packageDefinition[w]
|
|
useDefinitions[TextWriter.Null] // No output for uses
|
|
importDefinitions[w]
|
|
(typeDefinition[w])*
|
|
)
|
|
;
|
|
|
|
packageDefinition [TextWriter w]
|
|
: #( pkg:PACKAGE_DEF ({ Print(w, #pkg, " "); } identifier[w] { Print(w, ";"); PrintNL(w); })? )
|
|
;
|
|
|
|
useDefinitions [TextWriter w]
|
|
: #( USING_DIRECTIVES
|
|
(useDefinition[w])*
|
|
)
|
|
;
|
|
|
|
useDefinition [TextWriter w]
|
|
: #( USING_NAMESPACE_DIRECTIVE
|
|
identifier[w]
|
|
)
|
|
| #( USING_ALIAS_DIRECTIVE
|
|
alias:identifier[w]
|
|
pna:identifier[w]
|
|
)
|
|
;
|
|
|
|
importDefinitions [TextWriter w]
|
|
: #( IMPORTS
|
|
( { PrintNL(w); } (importDefinition[w])+ )?
|
|
) { PrintNL(w); }
|
|
;
|
|
|
|
importDefinition [TextWriter w]
|
|
: #( imp:IMPORT { Print(w, #imp, " "); }
|
|
identifier[w] { Print(w, ";"); PrintNL(w); }
|
|
)
|
|
;
|
|
|
|
typeDefinition [TextWriter w]
|
|
: #(cl:CLASS {inClassModifiers = true; }
|
|
modifiers[w] {inClassModifiers = false; }
|
|
id:IDENTIFIER { Print(w, "class "); Print(w, #id, " "); }
|
|
extendsClause[w]
|
|
implementsClause[w] { PrintNL(w); Print(w, "{"); PrintNL(w); indentLevel++; }
|
|
objBlock[w] { indentLevel--; Print(w, "}"); PrintNL(w); }
|
|
)
|
|
| #(INTERFACE
|
|
modifiers[w]
|
|
ifid:IDENTIFIER { Print(w, "interface "); Print(w, #ifid, " "); }
|
|
implementsClause[w] { PrintNL(w); Print(w, "{"); PrintNL(w); indentLevel++; }
|
|
interfaceBlock[w] { indentLevel--; Print(w, "}"); PrintNL(w); }
|
|
)
|
|
| #(ENUM
|
|
modifiers[w]
|
|
enmid:IDENTIFIER { Print(w, "enum "); Print(w, #enmid, " "); WriteStartEnum(#enmid); }
|
|
implementsClause[w] { PrintNL(w); Print(w, "{"); PrintNL(w); indentLevel++; }
|
|
enumBlock[w] { indentLevel--; Print(w, "}"); PrintNL(w); WriteEndEnum(); }
|
|
)
|
|
| #(ann:ANNOTATION
|
|
modifiers[w]
|
|
annid:IDENTIFIER { Print(w, "@interface "); Print(w, #annid, " "); PrintNL(w); Print(w, "{"); PrintNL(w); indentLevel++;}
|
|
objBlock[w] { indentLevel--; Print(w, "}"); PrintNL(w); }
|
|
)
|
|
;
|
|
|
|
typeSpec [TextWriter w]
|
|
: #(TYPE
|
|
( identifier[w]
|
|
| builtInType[w]
|
|
)
|
|
rankSpecifiers[w]
|
|
)
|
|
;
|
|
|
|
rankSpecifiers [TextWriter w]
|
|
: #( ARRAY_RANKS
|
|
( rankSpecifier[w]
|
|
)*
|
|
)
|
|
;
|
|
|
|
rankSpecifier [TextWriter w]
|
|
: #(ARRAY_RANK
|
|
( COMMA // Notice, we ignore dimensions.
|
|
)*
|
|
) { Print(w, "[]"); }
|
|
;
|
|
|
|
typeSpecArray [TextWriter w]
|
|
: #( ARRAY_DECLARATOR
|
|
typeSpecArray[w] { Print(w, "[]"); }
|
|
)
|
|
| type[w]
|
|
;
|
|
|
|
type [TextWriter w]
|
|
: identifier[w]
|
|
| builtInType[w]
|
|
;
|
|
|
|
builtInType [TextWriter w]
|
|
: tvo:VOID { Print(w, #tvo); }
|
|
| tbo:BOOL { Print(w, #tbo); }
|
|
| tst:STRING { Print(w, #tst); }
|
|
| tby:SBYTE { Print(w, #tby); }
|
|
| tch:"char" { Print(w, #tch); }
|
|
| tsh:"short" { Print(w, #tsh); }
|
|
| tin:"int" { Print(w, #tin); }
|
|
| tfl:"float" { Print(w, #tfl); }
|
|
| tlo:"long" { Print(w, #tlo); }
|
|
| tdo:"double" { Print(w, #tdo); }
|
|
| tuby: UBYTE { Print(w, #tuby); }
|
|
| tudec: DECIMAL { Print(w, #tudec); }
|
|
| tuint: UINT { Print(w, #tuint); }
|
|
| tulng: ULONG { Print(w, #tulng); }
|
|
| tush: USHORT { Print(w, #tush); }
|
|
| tb: BYTE { Print(w, #tb); }
|
|
;
|
|
|
|
modifiers [TextWriter w]
|
|
: #( MODIFIERS (modifier[w] { Print (w, " "); }
|
|
)* )
|
|
;
|
|
|
|
modifier [TextWriter w]
|
|
: mpr:"private" { Print(w, #mpr); }
|
|
| mpu:"public" { Print(w, #mpu); }
|
|
| mpt:"protected" { Print(w, #mpt); }
|
|
| mst:"static" { if (!inClassModifiers) {Print(w, #mst);} }
|
|
| mtr:"transient" { Print(w, #mtr); }
|
|
| mfi:FINAL { Print(w, #mfi); }
|
|
| mab:ABSTRACT { Print(w, #mab); }
|
|
| mna:"native" { Print(w, #mna); }
|
|
| mth:"threadsafe" { Print(w, #mth); }
|
|
| msy:"synchronized" { Print(w, #msy); }
|
|
| mco:"const" { Print(w, #mco); }
|
|
| mvo:"volatile" { Print(w, #mvo); }
|
|
| msf:"strictfp" { Print(w, #msf); }
|
|
;
|
|
|
|
extendsClause [TextWriter w]
|
|
//OK, OK, really we can only extend 1 class, but the tree stores a list so ....
|
|
: #(EXTENDS_CLAUSE
|
|
( { Print(w, "extends "); } identifier[w] ({ Print(w, ", "); } identifier[w])* { Print(w, " "); } )?
|
|
)
|
|
;
|
|
|
|
implementsClause [TextWriter w]
|
|
: #(IMPLEMENTS_CLAUSE
|
|
( { Print(w, "implements "); } identifier[w] ({ Print(w, ", "); } identifier[w])* { Print(w, " "); } )?
|
|
)
|
|
;
|
|
|
|
|
|
interfaceBlock [TextWriter w]
|
|
: #( MEMBER_LIST
|
|
( methodDecl[w] { Print(w, ";"); PrintNL(w); }
|
|
| variableDef[w] { Print(w, ";"); PrintNL(w); }
|
|
| typeDefinition[w]
|
|
)*
|
|
)
|
|
;
|
|
|
|
objBlock [TextWriter w]
|
|
: #( MEMBER_LIST
|
|
(
|
|
( { PrintNL(w); } ctorDef[w]
|
|
| { PrintNL(w); } methodDef[w]
|
|
| variableDef[w] { Print(w, ";"); }
|
|
| { PrintNL(w); } typeDefinition[w]
|
|
| { PrintNL(w); } #(STATIC_CTOR_DECL { Print(w, "static"); PrintNL(w); }
|
|
slist[w] )
|
|
| { PrintNL(w); } #(INSTANCE_INIT
|
|
slist[w] )
|
|
) { PrintNLIfReq(w); }
|
|
)*
|
|
)
|
|
;
|
|
|
|
// This enumblock is from Java 1.3, in theory enums can have methods, nested enums, ....
|
|
enumBlock [TextWriter w]
|
|
{ enumMembers.Clear(); }
|
|
: #( MEMBER_LIST ( alt1:IDENTIFIER { Print(w, #alt1); enumMembers.Add(#alt1); } ( alts:IDENTIFIER { Print(w, ", "); Print(w, #alts); enumMembers.Add(#alts); } )* { PrintNL(w); WriteEnumMembers(); } )? )
|
|
;
|
|
|
|
ctorDef [TextWriter w]
|
|
: #(CTOR_DECL
|
|
modifiers[w]
|
|
methodHead[w]
|
|
(slist[w])?)
|
|
;
|
|
|
|
methodDecl [TextWriter w]
|
|
: #(METHOD_DECL
|
|
modifiers[w]
|
|
typeSpec[w] { Print(w, " "); }
|
|
methodHead[w])
|
|
;
|
|
|
|
methodDef [TextWriter w]
|
|
: #(METHOD_DECL
|
|
modifiers[w]
|
|
typeSpec[w] { Print(w, " "); }
|
|
methodHead[w]
|
|
(slist[w])?
|
|
)
|
|
;
|
|
|
|
variableDef [TextWriter w]
|
|
: #(FIELD_DECL
|
|
modifiers[w]
|
|
typeSpec[w] { Print(w, " "); }
|
|
variableDeclarator[w] ( {Print(w, ", "); } variableDeclarator[w])*
|
|
//varInitializer[w]
|
|
)
|
|
;
|
|
|
|
parameterDef [TextWriter w]
|
|
: #(PARAMETER_FIXED
|
|
typeSpec[w] { Print(w, " "); }
|
|
id:IDENTIFIER { Print(w, #id); }
|
|
)
|
|
| #(PARAMS typeSpec[w] { Print(w, "... "); } ids:IDENTIFIER { Print(w, #ids); } )
|
|
;
|
|
|
|
objectinitializer [TextWriter w]
|
|
: #(INSTANCE_INIT
|
|
slist[w] )
|
|
;
|
|
|
|
variableDeclarator [TextWriter w]
|
|
: #( VAR_DECLARATOR
|
|
id:IDENTIFIER { Print(w, #id); }
|
|
(varInitializer[w])?
|
|
)
|
|
// | LBRACK variableDeclarator[w] { Print(w, "[]"); }
|
|
;
|
|
|
|
varInitializer [TextWriter w]
|
|
: #(VAR_INIT { Print(w, " = "); }
|
|
initializer[w])
|
|
;
|
|
|
|
initializer [TextWriter w]
|
|
: expression[w]
|
|
| arrayInitializer[w]
|
|
;
|
|
|
|
arrayInitializer [TextWriter w]
|
|
: #(ARRAY_INIT
|
|
{ Print(w, "{"); }
|
|
( initializer[w] ( { Print(w, ", "); } initializer[w] )* )?
|
|
{ Print(w, "}"); }
|
|
)
|
|
;
|
|
|
|
methodHead [TextWriter w]
|
|
: id:IDENTIFIER { Print(w, #id); }
|
|
#( FORMAL_PARAMETER_LIST
|
|
{ Print(w, "("); }
|
|
( parameterDef[w] ( { Print(w, ", "); } parameterDef[w] )* )?
|
|
{ Print(w, ") "); }
|
|
)
|
|
( throwsClause[w])? { PrintNL(w); }
|
|
;
|
|
|
|
throwsClause [TextWriter w]
|
|
: #( th:"throws" { Print(w, #th, " "); }
|
|
( identifier[w] ( { Print(w, ", "); } identifier[w] )* )?
|
|
)
|
|
;
|
|
|
|
identifier [TextWriter w]
|
|
: id:IDENTIFIER { Print(w, #id); }
|
|
| #( DOT id1:IDENTIFIER { Print(w, #id1); Print(w, "."); } identifier[w] )
|
|
;
|
|
|
|
identifierStar [TextWriter w]
|
|
: id:IDENTIFIER { Print(w, #id); }
|
|
| st:STAR { Print(w, "."); Print(w, #st); }
|
|
| #( DOT id1:IDENTIFIER { Print(w, #id1); Print(w, "."); } identifier[w] )
|
|
;
|
|
|
|
slist [TextWriter w]
|
|
: #( BLOCK { Print(w, "{"); PrintNL(w); indentLevel++; } (stat[w])* { indentLevel--; Print(w, "}"); PrintNL(w); } )
|
|
| EMPTY_STMT { Print(w, ";"); PrintNL(w); }
|
|
;
|
|
|
|
// Like a slist[] but we don't indent. Appears in switch alternatives
|
|
statementList [TextWriter w]
|
|
: #( STMT_LIST (stat[w])* )
|
|
;
|
|
|
|
stat [TextWriter w]
|
|
:(
|
|
typeDefinition[w]
|
|
| variableDef[w] { Print(w, ";"); }
|
|
| #(EXPR_STMT expression[w]) { Print(w, ";"); }
|
|
| #(LABEL_STMT id:IDENTIFIER { Print(w, #id, ": "); } stat[w])
|
|
| #(lif:IF { Print(w, #lif, " ("); }
|
|
expression[w] { Print(w, ")"); PrintNL(w); }
|
|
stat[w]
|
|
( #(ELSE { Print(w, "else"); PrintNL(w); }
|
|
stat[w])
|
|
)?
|
|
)
|
|
| #( fo:"for" { Print(w, #fo, " ("); }
|
|
#(FOR_INIT (variableDef[w])* (expression[w] ( { Print(w, ", "); } expression[w])* )?) { Print(w, "; "); }
|
|
#(FOR_COND (expression[w])?) { Print(w, "; "); }
|
|
#(FOR_ITER (expression[w] ( { Print(w, ", "); } expression[w])* )?) { Print(w, ")"); PrintNL(w); }
|
|
stat[w]
|
|
)
|
|
| #(fe:"foreach" { Print(w, "for ("); }
|
|
variableDef[w] { Print(w, " : "); }
|
|
expression[w] { Print(w, ")"); PrintNL(w); }
|
|
stat[w]
|
|
)
|
|
| #(wh:"while" { Print(w, #wh, " ("); }
|
|
expression[w] { Print(w, ")"); PrintNL(w); }
|
|
stat[w]
|
|
)
|
|
| #(dd:"do" { Print(w, #dd); PrintNL(w); }
|
|
stat[w] { Print(w, "while ("); }
|
|
expression[w] { Print(w, ");"); }
|
|
)
|
|
| #(gt:"goto" { Print(w, "// TODO: CS2J: goto is not supported by Java."); PrintNL(w); Print(w, "continue "); } gid:IDENTIFIER { Print(w, #gid); Print(w, ";"); } )
|
|
| #(br:"break" { Print(w, #br); } ( { Print(w, " "); } bid:IDENTIFIER { Print(w, #bid); } )? { Print(w, ";"); } )
|
|
| #(co:"continue" { Print(w, #co); } ( { Print(w, " "); } cid:IDENTIFIER { Print(w, #cid); } )? { Print(w, ";"); } )
|
|
| #(re:"return" { Print(w, #re); } ( { Print(w, " "); } expression[w])? { Print(w, ";"); } )
|
|
| #(sw:"switch" { Print(w, #sw, " ("); }
|
|
expression[w] { Print(w, ")"); PrintNL(w); Print(w, "{"); indentLevel++; PrintNL(w); }
|
|
(caseGroup[w])*
|
|
) { indentLevel--; Print(w, "}"); }
|
|
| #(th:"throw" { Print(w, #th, " "); } expression[w] { Print(w, ";"); } )
|
|
| #(sy:"synchronized" { Print(w, #sy, " ("); }
|
|
expression[w] { Print(w, ")"); PrintNL(w); }
|
|
stat[w]
|
|
)
|
|
| tryBlock[w]
|
|
| slist[w] // nested SLIST (keving: should this be surrounded by braces?)
|
|
// uncomment to make assert JDK 1.4 stuff work
|
|
// | #("assert" expression[w] (expression[w])?)
|
|
| ctorCall[w] { Print(w, ";"); }
|
|
) { PrintNLIfReq(w); }
|
|
;
|
|
|
|
caseGroup [TextWriter w]
|
|
: #(SWITCH_SECTION (#(ca:"case" { Print(w, #ca, " "); }
|
|
expression[w]) { Print(w, ":"); PrintNL(w); indentLevel++; }
|
|
| de:"default" { Print(w, #de, ":"); PrintNL(w); indentLevel++; } )+
|
|
statementList[w] ) { indentLevel--; }
|
|
;
|
|
|
|
tryBlock [TextWriter w]
|
|
: #( tr:"try" { Print(w, #tr); PrintNL(w); }
|
|
slist[w]
|
|
(handler[w])*
|
|
(#(fi:"finally" { Print(w, #fi); PrintNL(w); }
|
|
slist[w]
|
|
))?
|
|
)
|
|
;
|
|
|
|
handler [TextWriter w]
|
|
: #( ca:"catch" { Print(w, #ca, " ("); }
|
|
( typeSpec[w] | variableDef[w]) { Print(w, ")"); PrintNL(w); }
|
|
slist[w]
|
|
)
|
|
;
|
|
|
|
elist [TextWriter w]
|
|
: #( EXPR_LIST
|
|
( expression[w] ( { Print(w, ", "); } expression[w] )* )?
|
|
)
|
|
;
|
|
|
|
expression [TextWriter w]
|
|
: #(EXPR expr[w])
|
|
;
|
|
|
|
expr [TextWriter w]
|
|
// QUESTION is right associative in C# and left-associative in Java, but we always parenthesize :-)
|
|
: #(QUESTION { Print(w, "( "); } expr[w] { Print(w, " ? "); } expr[w] { Print(w, " : "); } expr[w] { Print(w, " )"); }) // trinary operator
|
|
// binary operators...
|
|
| (ASSIGN|PLUS_ASSIGN|MINUS_ASSIGN|STAR_ASSIGN|DIV_ASSIGN
|
|
|MOD_ASSIGN|SHIFTR_ASSIGN|BSR_ASSIGN|SHIFTL_ASSIGN|BIN_AND_ASSIGN
|
|
|BIN_XOR_ASSIGN|BIN_OR_ASSIGN|LOG_OR|LOG_AND|BIN_OR|BIN_XOR|BIN_AND|NOT_EQUAL
|
|
|EQUAL|LTHAN|GTHAN|LTE|GTE|SHIFTL|SHIFTR|BSR|PLUS|MINUS|DIV|MOD|STAR|INSTANCEOF
|
|
)
|
|
{
|
|
AST op = #expr;
|
|
AST left = op.getFirstChild();
|
|
AST right = left.getNextSibling();
|
|
bool lp = false;
|
|
bool rp = false;
|
|
switch ( comparePrecedence(op,left) )
|
|
{
|
|
case -1 :
|
|
lp = true;
|
|
break;
|
|
case 0 :
|
|
if (op.Type == ASSIGN) lp = true; // ASSIGN/QUESTION is right associative in C#
|
|
break;
|
|
case 1:
|
|
break;
|
|
}
|
|
|
|
switch ( comparePrecedence(op,right) )
|
|
{
|
|
case -1:
|
|
rp = true;
|
|
break;
|
|
case 0:
|
|
if (op.Type != ASSIGN) rp = true; // All operators except ASSIGN/QUESTION are left associative in C#
|
|
break;
|
|
case 1:
|
|
break;
|
|
}
|
|
|
|
if ( lp ) Print(w, "(");
|
|
expr(left,w);
|
|
if ( lp ) Print(w, ")");
|
|
|
|
Print(w, " "+#op.getText()+" ");
|
|
|
|
if ( rp ) Print(w, "(");
|
|
expr(right,w); // manually invoke
|
|
if ( rp ) Print(w, ")");
|
|
}
|
|
|
|
| (INC|DEC|BIN_NOT|LOG_NOT|UNARY_MINUS|UNARY_PLUS)
|
|
{
|
|
AST op = #expr;
|
|
AST opnd = op.getFirstChild();
|
|
bool p = false;
|
|
if ( comparePrecedence(op,opnd) == -1) {
|
|
p = true;
|
|
}
|
|
Print(w, op.getText());
|
|
if ( p ) Print(w, "(");
|
|
expr(opnd, w);
|
|
if ( p ) Print(w, ")");
|
|
}
|
|
|
|
| #( POST_INC_EXPR expr[w] {Print(w, "++");} )
|
|
| #( POST_DEC_EXPR expr[w] {Print(w, "--");} )
|
|
| primaryExpression[w]
|
|
;
|
|
|
|
|
|
|
|
primaryExpression [TextWriter w]
|
|
: id:IDENTIFIER { Print(w, #id); }
|
|
| #( MEMBER_ACCESS_EXPR
|
|
( expr[w] { Print(w, "."); }
|
|
( did:IDENTIFIER { Print(w, #did); }
|
|
| arrayIndex[w]
|
|
| dth:"this" { Print(w, #dth); }
|
|
| dcl:"class" { Print(w, #dcl); }
|
|
| #( dne:"new" dni:IDENTIFIER { Print(w, #dne, " "); Print(w, dni, "("); } elist[w] { Print(w, ")"); } )
|
|
| dsu:"super" { Print(w, #dsu); }
|
|
)
|
|
| { Print(w, "."); } #(ARRAY_DECLARATOR typeSpecArray[w] { Print(w, "[]"); } )
|
|
| { Print(w, "."); } builtInType[w] (ddcl:"class" { Print(w, #ddcl); } )?
|
|
)
|
|
)
|
|
| arrayIndex[w]
|
|
| #(INVOCATION_EXPR primaryExpression[w] { Print(w, "("); } elist[w] { Print(w, ")"); })
|
|
| #(CAST_EXPR { Print(w, "(("); } typeSpec[w] { Print(w, ")("); } expr[w] { Print(w, "))"); } )
|
|
| newExpression[w]
|
|
| constant[w]
|
|
| su:"super" { Print(w, #su); }
|
|
| tr:"true" { Print(w, #tr); }
|
|
| fa:"false" { Print(w, #fa); }
|
|
| th:"this" { Print(w, #th); }
|
|
| nu:NULL { Print(w, #nu); }
|
|
| typeSpec[w] // type name used with instanceof
|
|
// javaTxt = text to be printed
|
|
// env = map from env-vars to AST
|
|
| javaWrapper[w]
|
|
;
|
|
|
|
javaWrapper [TextWriter w]
|
|
{ string javaTxt = ""; }
|
|
: #( JAVAWRAPPER javaTemplate:IDENTIFIER { javaTxt = javaTemplate.getText(); }
|
|
( { StringWriter sw = new StringWriter();
|
|
bool saveDoIndent = doIndent;
|
|
doIndent = false;
|
|
}
|
|
v:IDENTIFIER (expression[sw] | expr[sw] | elist[sw] )
|
|
{ javaTxt = javaTxt.Replace(#v.getText(), sw.ToString());
|
|
sw.Close();
|
|
doIndent = saveDoIndent; } )*
|
|
)
|
|
{ Print(w, javaTxt); }
|
|
;
|
|
|
|
ctorCall [TextWriter w]
|
|
: #( THIS { Print(w, "this("); } elist[w] { Print(w, ")"); })
|
|
| #( BASE { Print(w, "super("); } elist[w] { Print(w, ")"); })
|
|
;
|
|
|
|
arrayIndex [TextWriter w]
|
|
: #(ELEMENT_ACCESS_EXPR expr[w] { Print(w, "["); } elist[w] { Print(w, "]"); } )
|
|
;
|
|
|
|
constant [TextWriter w]
|
|
: it:INT_LITERAL { Print(w, #it); }
|
|
| ch:CHAR_LITERAL { Print(w, #ch); }
|
|
| st:STRING_LITERAL { Print(w, #st); }
|
|
| fl:NUM_FLOAT { Print(w, #fl); }
|
|
| db:DOUBLE_LITERAL { Print(w, #db); }
|
|
| flt:FLOAT_LITERAL { Print(w, #flt); }
|
|
| lo:LONG_LITERAL { Print(w, #lo); Print(w, "L"); }
|
|
| ul:ULONG_LITERAL { Print(w, #ul); Print(w, "L"); }
|
|
| de:DECIMAL_LITERAL { Print(w, #de, "/* Unsupported Decimal Literal */"); }
|
|
;
|
|
|
|
newExpression [TextWriter w]
|
|
: #( ne:OBJ_CREATE_EXPR { Print(w, #ne, " "); }
|
|
typeSpec[w]
|
|
{ Print(w, "("); } elist[w] { Print(w, ")"); }
|
|
( { PrintNL(w); indentLevel++; Print(w, "{"); PrintNL(w); indentLevel++; }
|
|
objBlock[w]
|
|
{ indentLevel--; Print(w, "}"); indentLevel--; PrintNL(w); }
|
|
)?
|
|
)
|
|
| #( na:ARRAY_CREATE_EXPR { Print(w, #na, " "); }
|
|
typeSpec[w]
|
|
( arrayInitializer[w] //rankSpecifiers[w]!
|
|
| { Print(w, "["); } elist[w] {Print(w, "]"); }
|
|
rankSpecifiers[w] ( arrayInitializer[w] )?
|
|
)
|
|
)
|
|
;
|
|
|
|
// newArrayDeclarator [TextWriter w]
|
|
// : #( ARRAY_DECLARATOR (newArrayDeclarator[w])? { Print(w, "["); }(expression[w])? { Print(w, "]"); })
|
|
// ;
|