2003-12-05 Cesar Lopez Nataren <cesar@ciencias.unam.mx>
[mono.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / jscript-lexer-parser.g
index 97e4e0a2c757cac85b9a42f125d8c6c654ba3a3c..9b5abee4450eb81eebb4662749af4b260fdd9e0e 100644 (file)
 // jscript-lexer-parser.g: EcmaScript Grammar written on antlr.
 //
 // Author:
-//      Cesar Octavio Lopez Nataren
+//      Cesar Lopez Nataren (cesar@ciencias.unam.mx)
 //
-// (C) 2003, Cesar Octavio Lopez Nataren, <cesar@ciencias.unam.mx>
+// (C) 2003, Cesar Lopez Nataren
 //
 
-
 options {
-    language = "CSharp";
-    namespace =  "Microsoft.JScript";
+       language = "CSharp";
+       namespace = "Microsoft.JScript";
 }
 
-
+//
 // Parser
-class JScriptParser extends Parser;
-
-// Program, see section 14 from Ecma-262, page 75.
-program
-    : 
-        source_elements
-    ;
-
-
-source_elements        
-    : 
-       source_element (source_elements | )
-    ;
-
-
-// See Section 14 from Ecma-262, page 75.
-source_element
-    : 
-       statement
-    |
-       function_declaration
-    ;
-
-
-// Statement, see section 12 from Ecma-262, page 61.
-statement
-    : 
-       block       
-    |
-        variable_statement
-    |
-       empty_statement
-    |
-       if_statement        
-    |
-       iteration_statement
-    |
-       continue_statement
-    |
-       break_statement
-    |
-       return_statement
-    |
-       with_statement
-    |
-       switch_statement
-    |
-       throw_statement     
-    |
-       labelled_statement
-    |
-       try_statement
-    ;
-
-
-block: LBRACE (statement_list | ) RBRACE 
-    ;
-
-
-empty_statement: SEMI_COLON ;
-
-
-if_statement
-    :
-       "if" LPAREN expression RPAREN statement (("else")=> "else" statement)?    
-    ;
-
-
-// See, Ecma-262 3d. Edition, page 64.
-// FIXME: more options left to implement.
-iteration_statement
-    :
-       "do" statement "while" LPAREN expression RPAREN SEMI_COLON
-    |
-       "while" LPAREN expression RPAREN statement
-    |
-       "for" LPAREN left_hand_side_expression "in" expression RPAREN statement
-    ;
-
-
-// ContinueStatement, Ecma-262, section 12.7
-// FIXME: Make sure that no LineSeparator appears between the continue keyword and the identifier or semicolon
-continue_statement: "continue" (IDENTIFIER | ) SEMI_COLON ;
-
-
-// BreakStatement, Ecma-262, section 12.8
-// FIXME: Make sure that no LineSeparator appears between the break keyword and the identifier or semicolon
-break_statement: "break" (IDENTIFIER | ) SEMI_COLON ;
-
+//
 
-// ReturnStatement, Ecma-262, section 12.9
-// FIXME: Make sure that no LineSeparator appears between the return keyword and the identifier or semicolon
-return_statement: "return" (expression | ) SEMI_COLON ;
+class JScriptParser extends Parser;
+options {
+       defaultErrorHandler = false;
+}
 
+program returns [ScriptBlock prog]
+{ prog = new ScriptBlock (); }
+       : source_elements [prog.src_elems]
+       ;
+
+source_elements [Block elems]
+       : (source_element [elems, elems.parent])*
+       ;
+
+source_element [Block elems, AST parent]
+{ AST stm = null; }
+       : stm = statement [parent]
+         { 
+                 if (stm != null) {
+                         elems.Add (stm); 
+                         Console.WriteLine ("DEBUG::src_elem::Add::{0}", 
+                                            stm.ToString ());
+                 }
+         }
+       | stm = function_decl_or_expr [parent]
+          {
+                 if (stm != null)
+                         elems.Add (stm);
+                         Console.WriteLine ("DEBUG:src_elem::Add (function)");
+         }
+       ;
+
+function_decl_or_expr [AST parent] returns [AST func]
+{
+       func = null;
+       bool is_func_exp = false;
+       FormalParameterList p = null;
+       Block body = null;
+}
+       : "function" (id:IDENTIFIER | { is_func_exp = true; } ) 
+         OPEN_PARENS (p = formal_param_list | ) CLOSE_PARENS 
+         (COLON type_annot:IDENTIFIER | )
+         {
+               if (is_func_exp)
+                       if (type_annot == null)
+                               func = new FunctionExpression (parent, String.Empty, p,
+                                                              null, null);
+                       else 
+                               func = new FunctionExpression (parent, String.Empty, p,
+                                                              type_annot.getText (), null);
+               else if (type_annot == null)
+                       func = new FunctionDeclaration (parent, id.getText (), p, null, null);
+                    else 
+                       func = new FunctionDeclaration (parent, id.getText (), p, 
+                                                       type_annot.getText (), null);
+         }
+         OPEN_BRACE 
+                 body = function_body [func] 
+                 { ((FunctionDeclaration) func).Function.body = body; } 
+         CLOSE_BRACE
+       ;
+
+function_body [AST parent] returns [Block elems]
+{
+       elems = new Block (parent);
+}
+       : source_elements [elems]
+       ;
 
-// WithStatement, see Ecma-262 3d. Edition, section 12.8, page 67.
-with_statement
-    : 
-       "with" LPAREN expression RPAREN statement 
-    ;
+formal_param_list returns [FormalParameterList p]
+{
+       p = new FormalParameterList ();
+}
+       : i:IDENTIFIER (COLON t1:IDENTIFIER { p.Add (i.getText (), t1.getText ()); } 
+                      | { p.Add (i.getText (), "Object"); } 
+                      )
+         (COMMA g:IDENTIFIER (COLON t2:IDENTIFIER { p.Add (g.getText (), t2.getText ()); } 
+                             | { p.Add (g.getText (), "Object"); }
+                             )
+         )*
+       ;
 
+//
+// Statements
+//
 
-switch_statement
-    :
-       "switch" LPAREN expression RPAREN case_block
-    ;
+statement [AST parent] returns [AST stm]
+{ stm = null; }
+       : stm = expr_stm [parent] SEMI_COLON
+       | stm = var_stm [parent]
+       | empty_stm
+       | stm = if_stm [parent]
+       | iteration_stm [parent]
+       | stm = continue_stm
+       | stm = break_stm
+       | stm = return_stm [parent]
+       | stm = with_stm [parent]
+       | switch_stm [parent]
+       | stm = throw_stm [parent]
+       | try_stm
+       ;
+
+block
+       : OPEN_BRACE (statement [null])* CLOSE_BRACE
+       ;
+
+try_stm
+       : "try" block
+         ((catch_exp (finally_exp | ) | ) | finally_exp)
+       ;
+
+catch_exp
+       : "catch" OPEN_PARENS IDENTIFIER CLOSE_PARENS block
+       ;
+
+finally_exp
+       : "finally" block
+       ;
+
+throw_stm [AST parent] returns [AST t]
+{
+       t = null;
+       AST e = null;
+}
+       : "throw" e = expr [parent] SEMI_COLON
+         {
+                 t = new Throw (e);
+         }
+       ;
 
+switch_stm [AST parent]
+       : "switch"  OPEN_PARENS expr [parent] CLOSE_PARENS case_block
+       ;
 
 case_block
-    :
-       LBRACE (case_clauses | ) (default_clause (case_clauses | ) | ) RBRACE
-    ;
-
-
-case_clauses: (case_clause)+ ;
-
-case_clause
-    : 
-       "case" expression COLON (statement_list | )
-    ;
-
+       : OPEN_BRACE case_clauses  default_clause case_clauses CLOSE_BRACE
+       ;
 
 default_clause
-    : 
-       "default" COLON (statement_list | )
-    ;
-
-
-labelled_statement
-    :
-       IDENTIFIER COLON statement
-    ;
-
-
-// ThrowStatement, Ecma-262, section 12.13
-// FIXME: Make sure no LineSeparator appears between the throw keyword and the expression or semicolon.
-throw_statement: "throw" expression SEMI_COLON ;
-
+       : "default" COLON statement_list
+       ;
 
-// See section 12.14 from Ecma-262, 3d. Edition.
-try_statement
-    : 
-       "try" block ((catch_exp (finally_exp | )) | finally_exp)
-    ;
+case_clauses
+       : (case_clause)*
+       ;
 
+case_clause
+       : "case" expr [null] COLON statement_list
+       ;
+
+with_stm [AST parent] returns [AST with]
+{
+       with = null;
+       AST exp, stm;
+       exp = stm = null;
+}
+       : "with" OPEN_PARENS exp = expr [parent] CLOSE_PARENS stm = statement [null]
+         {
+                 with = new With (exp, stm);  
+         }     
+       ;
+
+return_stm [AST parent] returns [AST r]
+{
+       r = null;
+       AST e = null;
+}
+       : "return" (e = expr [parent] { r = new Return (e); } | ) SEMI_COLON
+       ;
 
-// NOTE: I call it catch_exp, to avoid confusion on antlr.
-catch_exp: "catch" LPAREN IDENTIFIER RPAREN block ;
+break_stm returns [AST b]
+{
+       b = new Break ();
+}
+       : "break" ( id:IDENTIFIER
+                   { ((Break) b).identifier = id.getText (); }
+                 | { ((Break) b).identifier = String.Empty; } ) SEMI_COLON
+       ;
+       
+continue_stm returns [AST cont]
+{ cont = new Continue (); }
+       : "continue" ( id:IDENTIFIER 
+                      { ((Continue) cont).identifier = id.getText (); } 
+                    | { ((Continue) cont).identifier = String.Empty; } ) SEMI_COLON
+       ;
+
+iteration_stm [AST parent]
+       : "do" statement [null] "while" OPEN_PARENS expr [parent] CLOSE_PARENS SEMI_COLON
+       | "while" OPEN_PARENS expr [parent] CLOSE_PARENS statement [null]
+       | "for" OPEN_PARENS inside_for [parent] CLOSE_PARENS statement [null]
+       ;
+
+inside_for [AST parent]
+       // We must check the NoIn restriction
+       : (expr [parent] | ) SEMI_COLON (expr [parent] | ) SEMI_COLON (expr [parent] | )
+       // We must keep a counter c, c tells us how many decls are
+       // done, in order to interrupt if c > 1 and we are inside a "in"
+       | "var" (var_decl_list [null, null]
+                 ( SEMI_COLON (expr [parent] | ) SEMI_COLON (expr [parent] | )
+                 | "in" expr [parent]))
+       // FIXME: left_hand_side_expr in exp rule, missing
+       ;
+       
+if_stm [AST parent] returns [AST ifStm]
+{
+       ifStm = null;
+       AST cond, true_stm, false_stm;
+       cond = true_stm = false_stm = null;
+}
+       : "if" OPEN_PARENS cond = expr [parent] CLOSE_PARENS true_stm = statement [null]
+         (("else")=> "else" false_stm = statement [null] | )
+         {
+                 ifStm = new If (cond, true_stm, false_stm);
+         }
+       ;
+
+empty_stm
+       : SEMI_COLON
+       ;
+
+var_stm [AST parent] returns [VariableStatement var_stm]
+{ var_stm = new VariableStatement (); }
+       : "var" var_decl_list [var_stm, parent] SEMI_COLON
+       ;
+
+var_decl_list [VariableStatement var_stm, AST parent]
+{ VariableDeclaration var_decln = null; }
+       : var_decln = var_decl [parent]
+         { 
+               if (var_decln != null && var_stm != null)
+                       var_stm.Add (var_decln);
+         }
+         (COMMA var_decln = var_decl [parent]
+         { 
+                 if (var_decln != null && var_stm != null) 
+                         var_stm.Add (var_decln);
+         }
+         )*
+       ;
+       
+
+var_decl [AST parent] returns [VariableDeclaration var_decl]
+{ 
+       var_decl = null;
+       AST init = null;
+}
+       : id:IDENTIFIER (COLON type_annot:IDENTIFIER | )
+         (init = initializer [parent]
+          { 
+                 if (type_annot == null)
+                         var_decl = new VariableDeclaration (parent, id.getText (), null , init);
+                 else 
+                         var_decl = new VariableDeclaration (parent, id.getText (), type_annot.getText () , init); 
+          }
+         | 
+          {
+                 if (type_annot == null)
+                         var_decl = new VariableDeclaration (parent, id.getText (), null, null);
+                 else
+                         var_decl = new VariableDeclaration (parent, id.getText (), type_annot.getText (), null);
+          })
+       ;
+
+initializer [AST parent] returns [AST init]
+{ init = null; }
+       : ASSIGN init = assignment_expr [parent]
+       ;
+
+expr_stm [AST parent] returns [AST e]
+{ e = null; }
+       : e = expr [parent]
+       ;
 
-// NOTE: I call it finally_exp, to avoid confusion on the Java/C# side.
-finally_exp: "finally" block ;
 
-    
 statement_list
-    :
-       statement (statement_list | )
-    ;
-
-// VariableStatement, see section 12.2 from Ecma-262 3td Edition, page 74.
-variable_statement
-    :
-        "var" variable_declaration_list SEMI_COLON
-    ;
-        
-
-variable_declaration_list
-    :
-        variable_declaration (COMMA variable_declaration_list | )
-    ;
-
-variable_declaration
-    :
-       IDENTIFIER (initialiser | )
-    ;
-    
-
-initialiser
-    :
-        ASSIGNMENT assignment_expression
-    ;                           
-
-// FIXME: a conditional_expression can be reduced to a postfixExpression wich 
-// is reduced to a left_hand_side_expression
-// AssignmentExpression, see section 11.13 from Ecma-262 3td. Edition, page 59.
-assignment_expression
-    :
-        conditional_expression
-//    |
-//        left_hand_side_expression assignment_operator assignment_expression
-    ;
-
-        
-assignment_operator
-    :
-       ASSIGNMENT 
-    |
-       MULTIPLICATION_ASSIGN 
-    |
-       DIVISION_ASSIGN 
-    |
-       REMAINDER_ASSIGN 
-    |
-       ADDITION_ASSIGN 
-    |
-       SUBSTRACTION_ASSIGN 
-    |
-       SIGNED_LEFT_SHIFT_ASSIGN 
-    |
-       SIGNED_RIGHT_SHIFT_ASSIGN 
-    |
-       UNSIGNED_RIGHT_SHIFT_ASSIGN 
-    |
-       BITWISE_AND_ASSIGN 
-    |
-       BITWISE_XOR_ASSIGN 
-    |
-       BITWISE_OR_ASSIGN
-    ;
-
-
-// ConditionalExpression, see section 11.12 from Ecma-262, page 58.
-conditional_expression
-    :
-        logical_or_expression (CONDITIONAL assignment_expression COLON assignment_expression | )
-    ;
-        
-
-
-// Binary Logical Operators, section 11.11 from Ecma-262 spec, page 58.
-logical_or_expression
-    :
-        logical_and_expression (LOGICAL_OR logical_or_expression | )
-    ;
-
-
-logical_and_expression
-    :
-        bitwise_or_expression (LOGICAL_AND logical_and_expression | )
-    ;
-
-
-// Binary Bitwise Operators, section 11.10 from Ecma-262 spec, page 57.
-bitwise_or_expression
-    :
-        bitwise_xor_expression (BITWISE_OR bitwise_or_expression | )
-    ;
-
-bitwise_xor_expression
-    :
-        bitwise_and_expression (BITWISE_XOR bitwise_xor_expression | )
-    ;
-
-
-bitwise_and_expression
-    :
-        equality_expression (BITWISE_AND bitwise_and_expression | )       
-    ;
-
-
-// Equality Operators, section 11.9 from Ecma-262 spec, page 54.
-// FIXME: more options left to implement
-equality_expression
-    :
-        relational_expression ((EQUALS | DOES_NOT_EQUALS | STRICT_EQUALS | STRICT_DOES_NOT_EQUALS) equality_expression | )
-    ;
-
-
-// Relational Operators, section 11.4 from Ecma-262 spec, page 52.
-// FIXME: more options left to implement
-relational_expression
-    :
-        shift_expression ((L_THAN | G_THAN | LE_THAN | GE_THAN | "instanceof" | "in" ) relational_expression | )
-    ;
-
-
-// Bitwise Shift Operators, section 11.7 from Ecma-262, page 51.
-// FIXME: more options left to implement
-shift_expression
-    :
-        additive_expression ((SIGNED_RIGHT_SHIFT | SIGNED_LEFT_SHIFT) shift_expression | )
-    ;
-
-
-
-// Additive Operators, section 11.6 from Ecma-262, page 50.
-// FIXME: more options left to implement
-additive_expression
-    :
-        multiplicative_expression ((PLUS | MINUS) additive_expression | )
-    ;
-
-
-
-// Multiplicative Operators, section 11.5 from Ecma-262, page 48.
-multiplicative_expression
-    :
-        unary_expression ((TIMES | DIVISION  | REMAINDER) multiplicative_expression | ) 
-    ;
-
-
-// Unary Operators,  Section 11.4 from Ecma-262, page 46.
-unary_expression
-    :
-        postfix_expression
-    |
-        ("delete" | "void" | "typeof" | INCREMENT | DECREMENT | PLUS | MINUS | BITWISE_NOT | LOGICAL_NOT) unary_expression
-    ;
-
-
-// Postfix Expressions, section 11.3 from Ecma-262, page 45.
-// FIXME: ensure that no LineTerminator appears between LeftHandSideExpression and INCREMENT and DECREMENT.
-postfix_expression
-    :
-        left_hand_side_expression (INCREMENT | DECREMENT | )
-    ;
-
-
-// FIXME: there's a problem with the NEW member_expression arguments rule from member expression
-// section 11.2 from Ecma-262 3td Edition, page 43.
-left_hand_side_expression
-    :
-        new_expression
-//    |
-//        call_expression
-    ;
-
-
-// FIXME: there's a problem with the NEW member_expression arguments rule from member expression
-new_expression
-    :
-        member_expression
-    |
-        "new" new_expression
-    ;
-
-// FIXME: more options left to implement
-call_expression
-    :
-       member_expression arguments (arguments | LSQUARE expression RSQUARE | DOT IDENTIFIER)*
-    ;
-
-
-// See Ecma-262, section 11.2, page 43.
-// FIXME: more options left to implement
-member_expression
-    :
-       (primary_expression | function_expression) (LSQUARE expression RSQUARE | DOT IDENTIFIER)*
-//    |
-//        "new" member_expression arguments
-    ;
-
-
-
-arguments
-    :
-        LPAREN (argument_list | ) RPAREN
-    ;
+       : (statement [null])*
+       ;
+
+expr [AST parent] returns [Expression e]
+{
+       e = new Expression ();
+       AST a = null;
+} 
+       : a = assignment_expr [parent] { e.Add (a); } 
+         (COMMA a = assignment_expr [parent] { e.Add (a); } )*
+       ;
+assignment_expr [AST parent] returns [AST assign_expr]
+{     
+       assign_expr = null;
+       JSToken op = JSToken.None;
+       AST left, right;
+       left = right = null;
+}
+       : ((left_hand_side_expr [parent] assignment_op)=> 
+           left = left_hand_side_expr [parent] op = assignment_op right = assignment_expr [parent]
+           {
+                 Binary a = new Binary (parent, left, right, op);
+                 Console.WriteLine ("\nDEBUG::jscript.g::assign_expr::ToString::" + a.ToString () + "\n");
+                 assign_expr = a;
+           }
+       | assign_expr = cond_expr [parent]
+       )
+       ;
+
+member_expr [AST parent] returns [AST mem_exp]
+{
+       mem_exp = null;
+}
+       : mem_exp = primary_expr [parent] member_aux [parent]
+       | "new" member_expr [parent] arguments [parent]
+       ;
+
+member_aux [AST parent]
+       : ( DOT IDENTIFIER member_aux [parent]
+         | (OPEN_BRACKET)=> OPEN_BRACKET expr [parent] CLOSE_BRACKET
+         |
+         )
+       ;
+
+new_expr [AST parent] returns [AST new_exp]
+{
+       new_exp = null; 
+       AST mem_exp = null;
+}
+       : mem_exp = member_expr [parent] { new_exp = mem_exp; }
+       ;
         
+call_expr [AST parent] returns [Call func_call]
+{
+       func_call = null;
+       AST member = null;
+       AST args1 = null;
+       AST args2 = null;
+}
+       : member = member_expr [parent] args1 = arguments [parent] args2 = call_aux [parent]
+         {
+                 func_call = new Call (parent, member, args1, args2);
+         }
+       ;
+
+call_aux [AST parent] returns [AST args]
+{
+       args = null;
+} 
+       : 
+       ( arguments [parent]
+       | OPEN_BRACKET expr [parent] CLOSE_BRACKET
+       | DOT IDENTIFIER
+       ) call_aux [parent]
+       |
+       ;
+
+arguments [AST parent] returns [Args args]
+{
+       Args tmp = new Args ();
+       args = null; 
+}
+       : OPEN_PARENS (arguments_list [tmp, parent] { args = tmp; } | ) CLOSE_PARENS
+       ;
 
-argument_list
-    :
-        assignment_expression (COMMA argument_list | )
-    ;
-
-// Expressions, section 11, from Ecma-262 3d Edition, page 40.
-// FIXME: more options left to implement
-primary_expression
-    :
-        THIS
-    |
-        IDENTIFIER
-    |
-        literal
-    |
-       array_literal
-    |
-       object_literal
-    |
-       LPAREN expression RPAREN
-    ;
-
-
-// Literals, section 7.8 from Ecma-262 3d Edition, page 16.
-// FIXME: more options left to implement
-literal
-    :
-       boolean_literal
-    |
-       null_literal
-    |
-       STRING_LITERAL
-    ;
-
-
-// FIXME: more options left to implement.
-array_literal
-    :
-       LSQUARE (elision | ) RSQUARE
-    ;
-
-
-elision: (COMMA)+ ;
-
+arguments_list [Args args, AST parent]
+{
+       AST a = null;
+}
+       : a = assignment_expr [parent] { args.Add (a); } 
+         (COMMA a = assignment_expr [parent] { args.Add (a); })*
+       ;
+
+left_hand_side_expr [AST parent] returns [AST lhe]
+{
+       lhe = null;
+       Call call = null;
+}
+       : (call_expr [parent])=> call = call_expr [parent] { lhe = call; }
+       | lhe = new_expr [parent]
+       ;
+
+postfix_expr [AST parent] returns [Unary post_expr]
+{
+       post_expr = null;
+       JSToken op = JSToken.None;
+       AST left = null;
+}
+       : left = left_hand_side_expr [parent] ( INCREMENT { op = JSToken.Increment; } 
+                                             | DECREMENT { op = JSToken.Decrement; } 
+                                             | )
+         {
+                 post_expr = new Unary (parent, left, op);
+         }
+       ;
+
+unary_expr [AST parent] returns [Unary unary_exprn]
+{
+       unary_exprn = null;
+       JSToken op = JSToken.None;
+       AST u_expr = null;
+}
+       : unary_exprn = postfix_expr [parent]
+       | op = unary_op u_expr = unary_expr [parent]
+         { 
+                 unary_exprn = new Unary (parent, u_expr, op); 
+         }
+       ;
+
+unary_op returns [JSToken unary_op]
+{ unary_op = JSToken.None; }
+       : "delete" { unary_op = JSToken.Delete; }
+       | "void" { unary_op = JSToken.Void; }
+       | "typeof" { unary_op = JSToken.Typeof; }
+       | INCREMENT { unary_op = JSToken.Increment; }
+       | DECREMENT { unary_op = JSToken.Decrement; }
+       | PLUS { unary_op = JSToken.Plus; }
+       | MINUS { unary_op = JSToken.Minus; }
+       | BITWISE_NOT { unary_op = JSToken.BitwiseNot; }
+       | LOGICAL_NOT { unary_op = JSToken.LogicalNot; }
+       ;
+
+multiplicative_expr [AST parent] returns [AST mult_expr]
+{
+       mult_expr = null;
+       Unary left = null;
+       AST right = null;
+}
+       : left = unary_expr [parent] right = multiplicative_aux [parent]
+         {
+                 if (right == null)
+                         mult_expr = left;
+                 else
+                         mult_expr = new Binary (parent, left, right, ((Binary) right).old_op);
+         }
+       ;
+
+multiplicative_aux [AST parent] returns [AST mult_aux]
+{
+       mult_aux = null;
+       JSToken mult_op = JSToken.None;
+       Unary left = null;
+       AST right = null;
+}
+       : (( MULT { mult_op = JSToken.Multiply; }
+          | DIVISION { mult_op = JSToken.Divide; }
+          | MODULE { mult_op = JSToken.Modulo; }
+          ) left = unary_expr [parent] right = multiplicative_aux [parent]
+            {
+                         if (right == null)
+                                 mult_aux = new Binary (parent, left, null, JSToken.None);
+                         else
+                                 mult_aux = new Binary (parent, left, right, ((Binary) right).old_op);
+                         ((Binary) mult_aux).old_op = mult_op;
+            }
+         | )
+       ;
+
+additive_expr [AST parent] returns [AST add_expr]
+{
+       add_expr = null;
+       AST left, right;
+       left = right = null;
+}
+       : left = multiplicative_expr [parent] right = additive_aux [parent]
+         {
+                         if (right == null)
+                                 add_expr = left;
+                         else
+                                 add_expr = new Binary (parent, left, right, ((Binary) right).old_op);
+         }
+       ;
+
+additive_aux [AST parent] returns [AST add_aux]
+{
+       add_aux = null;
+       JSToken op = JSToken.None;
+       AST left, right;
+       left = right = null;
+}
+       : (( PLUS { op = JSToken.Plus; }
+          | MINUS { op = JSToken.Minus; }
+          ) left = multiplicative_expr [parent] right = additive_aux [parent]
+            {
+                    if (right == null)
+                            add_aux = new Binary (parent, left, null, JSToken.None);
+                    else
+                            add_aux = new Binary (parent, left, right, ((Binary) right).old_op);
+                    ((Binary) add_aux).old_op = op;
+            }
+       | )
+       ;
+
+shift_expr [AST parent] returns [AST shift_expr]
+{
+       shift_expr = null;
+       AST left, right;
+       left = right = null;
+}
+       : left = additive_expr [parent] right = shift_aux [parent]
+         {
+                 if (right == null)
+                         shift_expr = left;
+                 else
+                         shift_expr = new Binary (parent, left, right, ((Binary) right).old_op);
+         }
+       ;
+
+shift_aux [AST parent] returns [AST shift_auxr]
+{ 
+       shift_auxr = null; 
+       JSToken op = JSToken.None;
+       AST left, right;
+       left = right = null;
+}
+       : (op = shift_op left = additive_expr [parent] right = shift_aux [parent]
+          {
+                  if (right == null)
+                          shift_auxr = new Binary (parent, left, null, JSToken.None);
+                  else
+                          shift_auxr = new Binary (parent, left, right, ((Binary) right).old_op);
+
+                  ((Binary) shift_auxr).old_op = op;
+          }
+         | )
+       ;
+
+shift_op returns [JSToken shift_op]
+{ shift_op = JSToken.None; }
+       : SHIFT_LEFT { shift_op = JSToken.LeftShift; }
+       | SHIFT_RIGHT { shift_op = JSToken.RightShift; }
+       | UNSIGNED_SHIFT_RIGHT { shift_op = JSToken.UnsignedRightShift; }
+       ;
+
+relational_expr [AST parent] returns [AST rel_expr]
+{
+       rel_expr = null;
+       AST left = null;
+       Relational right = null;
+}
+       : left = shift_expr [parent] right = relational_aux [parent]
+         {
+                 if (right == null)
+                         rel_expr = left;
+                 else
+                         rel_expr = new Relational (parent, left, right, right.old_op);
+         }
+       ;
+
+relational_aux [AST parent] returns [Relational rel_aux]
+{
+       rel_aux = null;
+       JSToken op = JSToken.None;
+       AST left = null;
+       Relational right = null;
+}
+       : (op = relational_op left = shift_expr [parent] right = relational_aux [parent]
+          {
+                  if (right == null)
+                         rel_aux = new Relational (parent, left, null, JSToken.None);
+                  else
+                          rel_aux = new Relational (parent, left, right, right.old_op);
+                  rel_aux.old_op = op;
+
+          }
+        | )
+       ;
+
+relational_op returns [JSToken rel_op]
+{ rel_op = JSToken.None; }
+       : LESS_THAN { rel_op = JSToken.LessThan; }
+       | GREATER_THAN { rel_op = JSToken.GreaterThan; }
+       | LESS_EQ { rel_op = JSToken.LessThanEqual; }
+       | GREATER_EQ { rel_op = JSToken.GreaterThanEqual; }
+       | "instanceof" { rel_op = JSToken.InstanceOf; }
+       ;
+
+
+equality_expr [AST parent] returns [AST eq_expr]
+{
+       eq_expr = null;
+       AST left = null;
+       Equality right = null;
+}
+       : left = relational_expr [parent] right = equality_aux [parent]
+         {
+                 if (right == null)
+                         eq_expr = left;
+                 else {
+                         eq_expr = new Equality (parent, left, right, right.old_op);
+                 }
+         }
+       ;
+
+equality_aux [AST parent] returns [Equality eq_aux]
+{
+       eq_aux = null;
+       AST left = null;
+       Equality right = null;
+       JSToken op = JSToken.None;
+}
+       : (op = equality_op left = relational_expr [parent] right = equality_aux [parent]
+          {
+                  if (right == null)
+                         eq_aux = new Equality (parent, left, null, JSToken.None);
+                  else
+                         eq_aux = new Equality (parent, left, right, right.old_op);
+
+                 eq_aux.old_op = op;
+          }
+         | )
+       ;
+
+equality_op returns [JSToken eq_op]
+{ eq_op = JSToken.None; }
+       : EQ { eq_op = JSToken.Equal; }
+       | NEQ { eq_op = JSToken.NotEqual; }
+       | STRICT_EQ { eq_op = JSToken.StrictEqual; }
+       | STRICT_NEQ { eq_op = JSToken.StrictNotEqual; }
+       ;
+
+bitwise_and_expr [AST parent] returns [AST bit_and_expr]
+{
+       bit_and_expr = null;
+    AST left;
+       AST right;
+       left = null;
+       right = null;
+}
+       : left = equality_expr [parent]  right = bitwise_and_aux [parent]
+         {
+                 if (right == null)
+                         bit_and_expr = left;
+                 else
+                         bit_and_expr = new Binary (parent, left, right, JSToken.BitwiseAnd);
+         }
+       ;
+
+bitwise_and_aux [AST parent] returns [AST bit_and_aux]
+{
+       bit_and_aux = null;
+       AST left = null;
+       AST right = null;
+}
+       : (BITWISE_AND left = equality_expr [parent] right = bitwise_and_aux [parent]
+          {
+                  if (right == null)
+                          bit_and_aux = left;
+                  else
+                          bit_and_aux = new Binary (parent, left, right, JSToken.BitwiseAnd);
+          }
+         | )
+                 
+       ;
+
+bitwise_xor_expr [AST parent] returns [AST bit_xor_expr]
+{
+       bit_xor_expr = null;
+       AST left, right;
+       left = right = null;
+}
+       : left = bitwise_and_expr [parent] right = bitwise_xor_aux [parent]
+         {
+                 if (right == null)
+                         bit_xor_expr = left;
+                 else
+                         bit_xor_expr = new Binary (parent, left, right, JSToken.BitwiseXor);
+         }
+       ;
+
+bitwise_xor_aux [AST parent] returns [AST bit_xor_aux]
+{
+       bit_xor_aux = null;
+       AST left, right;
+       left = right = null;
+}
+       : (BITWISE_XOR left = bitwise_and_expr [parent] right = bitwise_xor_aux [parent]
+          {
+                 if (right == null)
+                         bit_xor_aux = left;
+                 else
+                         bit_xor_aux = new Binary (parent, left, right, JSToken.BitwiseXor);
+          }
+         | )
+       ;
+
+bitwise_or_expr [AST parent] returns [AST bit_or_expr]
+{ 
+       bit_or_expr = null;
+       AST left, right;
+       left = right = null;
+}
+       : left = bitwise_xor_expr [parent] right = bitwise_or_aux [parent]
+         {
+                 if (right == null)
+                         bit_or_expr = left;
+                 else
+                         bit_or_expr = new Binary (parent, left, right, JSToken.BitwiseOr);
+         }
+       ;
+
+bitwise_or_aux [AST parent] returns [AST bit_or_aux]
+{ 
+       bit_or_aux = null;
+       AST left, right;
+       left = right = null;
+}
+       : (BITWISE_OR left = bitwise_xor_expr [parent] right = bitwise_or_aux [parent]
+          {
+                  if (right == null)
+                          bit_or_aux = left;
+                  else
+                          bit_or_aux = new Binary (parent, left, right, JSToken.BitwiseOr);
+          }
+         | )
+       ;
+
+logical_and_expr [AST parent] returns [AST log_and_expr]
+{
+       log_and_expr = null;
+       AST left, right;
+       left = right = null;
+}
+       : left = bitwise_or_expr [parent] right = logical_and_aux [parent]
+         {
+                 if (right == null)
+                         log_and_expr = left;
+                 else
+                         log_and_expr = new Binary (parent, left, right, JSToken.LogicalAnd);
+         }
+       ;
+
+logical_and_aux [AST parent] returns [AST log_and_aux]
+{
+       log_and_aux = null;
+       AST left, right;
+       left = right = null;
+}
+       : (LOGICAL_AND left = bitwise_or_expr [parent] right = logical_and_aux [parent]
+          {
+                  if (right == null)
+                          log_and_aux = left;
+                  else
+                          log_and_aux = new Binary (parent, left, right, JSToken.LogicalAnd);
+          }
+         | )
+       ;
+
+logical_or_expr [AST parent] returns [AST log_or_expr]
+{ 
+       log_or_expr = null; 
+       AST left, right;
+       left = right = null;
+}
+       :  left = logical_and_expr [parent] right = logical_or_aux [parent]
+          {
+                 if (right == null)
+                         log_or_expr = left;
+                 else
+                         log_or_expr = new Binary (parent, left, right, JSToken.LogicalOr);
+          }
+                                                               
+       ;
+
+logical_or_aux [AST parent] returns [AST log_or_aux]
+{ 
+       AST left, right;
+       log_or_aux = null;
+       left = right = null;    
+}
+       : (LOGICAL_OR left = logical_and_expr [parent] right = logical_or_aux [parent]
+          {
+                 if (right == null)
+                         log_or_aux = left; 
+                 else
+                         log_or_aux = new Binary (parent, left, right, JSToken.LogicalOr);
+          }
+         | )
+       ;
+
+cond_expr [AST parent] returns [AST conditional]
+{
+       conditional = null; 
+       AST cond;
+       AST trueExpr, falseExpr;
+       cond = null;
+       trueExpr = falseExpr = null;
+}
+       : cond = logical_or_expr [parent]
+         (INTERR trueExpr = assignment_expr [parent]
+          COLON falseExpr = assignment_expr [parent]
+          { 
+                 if (trueExpr != null && falseExpr != null) {
+                         Conditional c = new Conditional (parent, (AST) cond, trueExpr, falseExpr); 
+                         conditional =  c;
+                 }
+          }
+         | { conditional = cond; } )
+
+       ;
+
+assignment_op returns [JSToken assign_op]
+{
+    assign_op = JSToken.None;
+}
+       : ASSIGN { assign_op = JSToken.Assign; }
+       | MULT_ASSIGN { assign_op = JSToken.MultiplyAssign; }
+       | DIV_ASSIGN { assign_op = JSToken.DivideAssign; }
+       | MOD_ASSIGN { assign_op = JSToken.ModuloAssign; }
+       | ADD_ASSIGN { assign_op = JSToken.PlusAssign; }
+       | SUB_ASSIGN { assign_op = JSToken.MinusAssign; }
+       | SHIFT_LEFT_ASSIGN { assign_op = JSToken.LeftShiftAssign; }
+       | SHIFT_RIGHT_ASSIGN { assign_op = JSToken.RightShiftAssign; }
+       | AND_ASSIGN { assign_op = JSToken.BitwiseAndAssign; }
+       | XOR_ASSIGN { assign_op = JSToken.BitwiseXorAssign; }
+       | OR_ASSIGN { assign_op = JSToken.BitwiseOrAssign; }
+       ;
+       
+
+primary_expr [AST parent] returns [AST prim_exp]
+{
+       prim_exp = null;
+       AST l = null;
+       Expression e = null;
+}
+       : p:"this" { prim_exp = new This (); }
+       | object_literal
+       | id:IDENTIFIER 
+         { 
+               Identifier ident = new Identifier (id.getText ());
+               prim_exp = (AST) ident;
+         }
+       | l = literal [parent] { prim_exp = l; }
+       | array_literal
+       | OPEN_PARENS e = expr [parent] { prim_exp = e; } CLOSE_PARENS
+       ; 
 
-// ObjectLiteral, see Ecma-262 3d. Edition, page 41 and 42.
 object_literal
-    : 
-       LBRACE (property_name_and_value_list | ) RBRACE ;
-
+       : OPEN_BRACE 
+          ((property_name COLON)=> property_name COLON assignment_expr [null] 
+           (COMMA property_name COLON assignment_expr [null])*
+          | (statement [null])*
+          )
+         CLOSE_BRACE
+       ;
+
+literal [AST parent] returns [AST l]
+{
+       l = null; 
+}
+       : "null"
+       | "true"
+         {
+                 BooleanLiteral bl = new BooleanLiteral (parent, true);
+                 l = bl;
+         }
+       | "false"
+         {
+                 BooleanLiteral bl = new BooleanLiteral (parent, false);
+                 l = bl;
+         }
+       | s:STRING_LITERAL
+         {
+                 StringLiteral str = new StringLiteral (s.getText ());
+                 l = str;
+         }      
+       | l = numeric_literal
+       ;
 
 property_name_and_value_list
-    :
-       property_name COLON assignment_expression (COMMA property_name_and_value_list | )
-    ;
+       : (property_name COLON primary_expr [null])+
+       ;
 
-
-// PropertyName
-// FIXME:  NumericLiteral missing.
 property_name
-    :
-       IDENTIFIER
-    |
-       STRING_LITERAL
-    ;
-
-
-//  Expression, see Ecma-262 spec, section 11.14, page 60. 
-expression: assignment_expression (COMMA  expression | ) ;
-
-
-// Function definition, see Section 13 from Ecma-262, page 71.
-function_declaration
-    :
-        "function" IDENTIFIER LPAREN (formal_parameter_list | ) RPAREN LBRACE function_body RBRACE
-    ;
-
-
-// This elems are just for compiling purposes.
-function_expression
-    :
-       "function" (IDENTIFIER | ) LPAREN (formal_parameter_list | ) RPAREN LBRACE function_body RBRACE
-    ;
-
-
-formal_parameter_list
-    :
-        IDENTIFIER (COMMA formal_parameter_list | )
-    ;
-
+       : (IDENTIFIER | STRING_LITERAL | numeric_literal) 
+       ;
 
-function_body
-    :
-        source_elements
-    ;
-
-
-boolean_literal
-    :
-       "true"
-    |
-       "false"
-    ;
+array_literal
+       : OPEN_BRACKET (primary_expr [null] (COMMA primary_expr [null])* | ) CLOSE_BRACKET
+       ;       
 
-null_literal
-    :
-       "null"
-    ;
+numeric_literal returns [NumericLiteral num_lit]
+{
+       num_lit = null;
+}
+       : d:DECIMAL_LITERAL { num_lit = new NumericLiteral (Convert.ToSingle (d.getText ())); }
+       | HEX_INTEGER_LITERAL
+       ;
+
+
+line_terminator
+       : LINE_FEED
+       | CARRIAGE_RETURN
+       | LINE_SEPARATOR
+       | PARAGRAPH_SEPARATOR
+       ;
+
+white_space
+       : TAB
+       | VERTICAL_TAB
+       | FORM_FEED
+       | SPACE
+       | NO_BREAK_SPACE
+       ;
 
+//
 // Lexer
+//
+
 class JScriptLexer extends Lexer;
+
 options {
-    charVocabulary='\u0000'..'\uFFFE';
-    testLiterals=false;
-    k = 4;
+       charVocabulary = '\u0000'..'\uFFFE';
+       testLiterals = false;
+       k = 3;
 }
 
-
-TAB 
-    : 
-        '\u0009'
-        { _ttype = Token.SKIP; }
-    ;
-        
-   
-VERTICAL_TAB
-    : 
-        '\u000B' 
-    ;
-
-
-FORM_FEED
-    :
-        '\u000C' 
+DECIMAL_LITERAL: ('0'  | ('1'..'9')('0'..'9')*) (DOT ('0'..'9')* | ) (('e' | 'E') (('+' | '-' | ) ('0'..'9')+) | )
     ;
 
-
-SPACE
-    :
-        '\u0020'
-        { _ttype =Token.SKIP; }
+HEX_INTEGER_LITERAL: '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
     ;
 
+STRING_LITERAL
+       : '"' (~('"' | '\\' | '\u000A' | '\u000D' | '\u2028' | '\u2029'))* '"' | 
+         '\''(~('\'' | '\\' | '\u000A' | '\u000D' | '\u2028' | '\u2029'))* '\''
+       ;
 
-NO_BREAK_SPACE
-    :
-        '\u00A0'
-    ;    
-
-// FIXME: find out possibles Unicode "space separator"
-// USP: 
-
-
-LINE_FEED
-    :
-        '\u000A'
-        { newline (); { _ttype =Token.SKIP; }}
-    ;
-
-
-CARRIGE_RETURN
-    :
-        '\u000D'
-        { newline (); { _ttype =Token.SKIP; }}
-    ;
-
-
-LINE_SEPARATOR
-    :
-        '\u2028'
-        { newline (); { _ttype =Token.SKIP; }}
-    ;
-
-
-PARAGRAPH_SEPARATOR
-    :
-        '\u2029'
-        { newline (); { _ttype =Token.SKIP; }}
-    ;
-
-
-
-
-// Punctuators
-
-LBRACE: '{' ;
-
-RBRACE: '}' ;
-
-LPAREN: '(' ;
-
-RPAREN: ')' ;
-
-LSQUARE: '[' ;
-
-RSQUARE: ']' ;
-
-DOT: '.' ;
-
-SEMI_COLON: ';' ;
-
-COMMA: ',' ;
-
-L_THAN: '<' ;
-
-G_THAN: '>' ;
-
-LE_THAN: "<=" ;
-
-GE_THAN: ">=" ;
-
-EQUALS: "==" ;
-
-DOES_NOT_EQUALS: "!=" ;
-
-STRICT_EQUALS: "===" ;
-
-STRICT_DOES_NOT_EQUALS: "!==" ;
-
-PLUS: '+' ;
-
-MINUS: '-' ;
-
-TIMES: '*' ;
 
-REMAINDER: '%' ;
+IDENTIFIER
+options { testLiterals = true; }
+       : ('a'..'z' | 'A'..'Z') ('a'..'z' | 'A'..'Z' | '0'..'9')*
+       ;
 
-INCREMENT: "++" ;
+//
+// Operators
+//
+DOT: '.';
+COMMA: ',';
 
+INCREMENT: "++";
 DECREMENT: "--";
+PLUS: '+';
+MINUS: '-';
+BITWISE_NOT: '~';
+LOGICAL_NOT: '!';
+
+MULT: '*';
+DIVISION: '/';
+MODULE: '%';
+ASSIGN: '=';
+
+
+SHIFT_LEFT: "<<";
+SHIFT_RIGHT: ">>";
+UNSIGNED_SHIFT_RIGHT: ">>>";
+       
+LESS_THAN: '<';
+GREATER_THAN: '>';
+LESS_EQ: "<=";
+GREATER_EQ: ">=";
+
+EQ: "==";
+NEQ: "!=";
+STRICT_EQ: "===";
+STRICT_NEQ: "!==";
+
+MULT_ASSIGN: "*=";
+DIV_ASSIGN: "/=";
+MOD_ASSIGN: "%=";
+ADD_ASSIGN: "+=";
+SUB_ASSIGN: "-=";
+SHIFT_LEFT_ASSIGN: "<<=";
+SHIFT_RIGHT_ASSIGN: ">>=";
+AND_ASSIGN: "&=";
+XOR_ASSIGN: "^=";
+OR_ASSIGN: "|=";
+INTERR: '?';
+LOGICAL_OR: "||";
+LOGICAL_AND: "&&";
+BITWISE_OR: '|';
+BITWISE_AND: '&';
+BITWISE_XOR: '^';
+
+
+OPEN_PARENS: '(';
+CLOSE_PARENS: ')';
+OPEN_BRACKET: '[';
+CLOSE_BRACKET: ']';
+OPEN_BRACE: '{';
+CLOSE_BRACE: '}';
 
-SIGNED_LEFT_SHIFT: "<<" ;
-
-SIGNED_RIGHT_SHIFT: ">>" ;
-
-UNSIGNED_RIGHT_SHIFT: ">>>" ;
-
-BITWISE_AND: '&' ;
-
-BITWISE_OR: '|' ;
-
-BITWISE_XOR: '^' ;
-
-LOGICAL_NOT: '!' ;
-
-BITWISE_NOT: '~' ;
-
-LOGICAL_AND: "&&" ;
-
-LOGICAL_OR: "||" ;
-
-CONDITIONAL: '?' ;
-
-COLON: ':' ;
-
-ASSIGNMENT: '=' ;
-
-ADDITION_ASSIGN: "+=" ;
-
-SUBSTRACTION_ASSIGN: "-=" ;
-
-MULTIPLICATION_ASSIGN: "*=" ;
-
-REMAINDER_ASSIGN: "%=" ;
-
-SIGNED_LEFT_SHIFT_ASSIGN: "<<=" ;
-
-SIGNED_RIGHT_SHIFT_ASSIGN: ">>=" ;
+//
+// Punctuators
+//
+SEMI_COLON: ';';
+COLON: ':';
 
-UNSIGNED_RIGHT_SHIFT_ASSIGN: ">>>=" ;
 
-BITWISE_AND_ASSIGN: "&=" ;
+//
+// Comments
+//
 
-BITWISE_OR_ASSIGN: "|=" ;
+SL_COMMENT
+       : "//" (~('\u000A' | '\u000D' | '\u2028' | '\u2029'))*
+         { $setType (Token.SKIP); }
+       ;
+
+ML_COMMENT
+       : "/*"
+       (options {
+               generateAmbigWarnings=false;
+       }
+       :
+               { LA(2)!='/' }? '*'
+       |       '\r' '\n'               { newline(); }
+       |       '\r'                    { newline(); }
+       |       '\n'                    { newline(); }
+       |       ~('*'|'\n'|'\r')
+       )*
+       "*/"
+       { $setType (Token.SKIP); }
+       ;
 
-BITWISE_XOR_ASSIGN: "^=" ;
+//
+// Line terminator tokens
+//
+LINE_FEED
+       : '\u000A' { $setType (Token.SKIP); newline (); }
+       ;
 
-DIVISION: '/' ;
+CARRIAGE_RETURN
+       : '\u000D' { $setType (Token.SKIP); newline ();}
+       ;
 
-DIVISION_ASSIGN: "/=" ;
+LINE_SEPARATOR
+       : '\u2028' { $setType (Token.SKIP); newline ();}
+       ;
 
+PARAGRAPH_SEPARATOR
+       : '\u2029' { $setType (Token.SKIP); newline ();}
+       ;
 
-// FIXME: this just temporal, in order to get into parsing
-STRING_LITERAL
-    : 
-        '"'!('a'..'z' | 'A'..'Z' | '\u0020')+'"'!
-    ;
+//
+// White space tokens
+//
+TAB
+       : '\u0009' { $setType (Token.SKIP); }
+       ;
 
+VERTICAL_TAB
+       : '\u000B' { $setType (Token.SKIP); }
+       ;
 
-// FIXME: this a temporal definition.
-//        We must handle the UNICODE charset, see section 7.6 of the Ecma-262 spec
-IDENTIFIER
-options { testLiterals=true; }
-    : 
-       ('a'..'z' | 'A'..'Z') ('a'..'z' | 'A'..'Z' | '0'..'9')*
-    ;
+FORM_FEED
+       : '\u000C' { $setType (Token.SKIP); }
+       ;
 
+SPACE
+       : '\u0020' { $setType (Token.SKIP); }
+       ;
 
-SL_COMMENT
-    :
-       "//" (~('\u000A' | '\u000D' | '\u2028' | '\u2029'))* { $setType (Token.SKIP); newline (); }
-    ;
+NO_BREAK_SPACE
+       : '\u00A0' { $setType (Token.SKIP); }
+       ;