// 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); }
+ ;