%start program /* tokens etc. */ %token BREAK %token FOR %token NEW %token VAR %token CONTINUE %token FUNCTION %token RETURN %token VOID %token DELETE %token IF %token THIS %token WHILE %token ELSE %token IN %token TYPEOF %token WITH %token RESERVED %token LIT_NULL %token LIT_TRUE %token LIT_FALSE %token NUMBER %token STRING %token IDENTIFIER %token EQ "==" %token LE "<=" %token GE ">=" %token NE "!=" %token LAN "&&" %token LOR "||" %token INC "++" %token DEC "--" %token SL "<<" %token SR ">>" %token SRR ">>>" %token IEQ "+=" %token DEQ "-=" %token MEQ "*=" %token SEQ "/=" %token AEQ "&=" %token OEQ "|=" %token XEQ "^=" %token MOEQ "%=" %token SLEQ "<<=" %token SREQ ">>=" %token SRREQ ">>>=" %left ',' %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|=" %left '?' ':' %left "&&" "||" %left '|' %left '^' %left '&' %left "==" "!=" %left '<' '>' "<=" ">=" %left "<<" ">>" ">>>" %left '+' '-' %left '*' '/' '%' %right DELETE TYPEOF "++" "--" UPLUS UMINUS VOID '~' '!' %right POSTFIX %left '.' %% /* rules */ primary_expr: THIS { (quote this) } | IDENTIFIER { $1 } | LIT_NULL { nil } | LIT_TRUE { t } | LIT_FALSE { nil } | NUMBER { $1 } | STRING { $1 } | '(' expr ')' { $2 } ; member_expr: primary_expr | member_expr '.' IDENTIFIER { `(get ,$1 ,$3) } | member_expr '[' expr ']' { `(if (integerp ,$3) (aref ,$1 ,$3) (get ,$1 ,$3)) } | NEW member_expr arguments { `(js-new ,$2 ,$3) } ; new_expr: member_expr | NEW new_expr { `(js-new ,$2) } ; call_expr: member_expr arguments { `(funcall ,$1 . ,$2) } | call_expr arguments { `(funcall ,$1 . ,$2) } | call_expr '[' expr ']' { `(if (integerp ,$3) (aref ,$1 ,$3) (get ,$1 ,$3)) } | call_expr '.' IDENTIFIER { `(get ,$1 ,$3) } ; arguments: '(' ')' { nil } | '(' arg_list ')' { (nreverse $2) } ; arg_list: assign_expr { (list $1) } | arg_list ',' assign_expr { (cons $3 $1) } ; lhs_expr: new_expr | call_expr ; pf_expr: lhs_expr | pf_expr {(setq ecma-newline-prohibitted t)} "++" %prec POSTFIX {`(1- (incf ,$1))} | pf_expr {(setq ecma-newline-prohibitted t))} "--" %prec POSTFIX {`(1+ (decf ,$1))} ; assign_expr: pf_expr | DELETE assign_expr | VOID assign_expr { `(progn ,$2 nil) } | TYPEOF assign_expr | "++" assign_expr { `(incf ,$2) } | "--" assign_expr { `(decf ,$2) } | '+' assign_expr %prec UPLUS { $2 } | '-' assign_expr %prec UMINUS { `(- ,$2) } | '~' assign_expr { `(lognot ,$2) } | '!' assign_expr { `(not ,$2) } | assign_expr '*' assign_expr { `(* ,$1 ,$3) } | assign_expr '/' assign_expr { `(/ ,$1 ,$3) } | assign_expr '%' assign_expr { `(% ,$1 ,$3) } | assign_expr '+' assign_expr { `(+ ,$1 ,$3) } | assign_expr '-' assign_expr { `(- ,$1 ,$3) } | assign_expr "<<" assign_expr { `(ash ,$1 ,$3) } | assign_expr ">>" assign_expr { `(ash ,$1 (- ,$3)) } | assign_expr ">>>" assign_expr { `(lsh ,$1 (- ,$3)) } | assign_expr '<' assign_expr { `(< ,$1 ,$3) } | assign_expr '>' assign_expr { `(> ,$1 ,$3) } | assign_expr "<=" assign_expr { `(<= ,$1 ,$3) } | assign_expr ">=" assign_expr { `(>= ,$1 ,$3) } | assign_expr "==" assign_expr { `(eql ,$1 ,$3) } | assign_expr "!=" assign_expr { `(not (eql ,$1 ,$3)) } | assign_expr "&&" assign_expr { `(and ,$1 ,$3) } | assign_expr "||" assign_expr { `(or ,$1 ,$3) } | assign_expr '|' assign_expr { `(logior ,$1 ,$3) } | assign_expr '&' assign_expr { `(logand ,$1 ,$3) } | assign_expr '^' assign_expr { `(logxor ,$1 ,$3) } | assign_expr '=' assign_expr { `(setf ,$1 ,$3) } | assign_expr "*=" assign_expr { `(setf ,$1 (* ,$1 ,$3)) } | assign_expr "/=" assign_expr { `(setf ,$1 (/ ,$1 ,$3)) } | assign_expr "%=" assign_expr { `(setf ,$1 (% ,$1 ,$3)) } | assign_expr "+=" assign_expr { `(incf ,$1 ,$3) } | assign_expr "-=" assign_expr { `(decf ,$1 ,$3) } | assign_expr "<<=" assign_expr { `(setf ,$1 (ash ,$1 ,$3)) } | assign_expr ">>=" assign_expr { `(setf ,$1 (ash ,$1 (- ,$3))) } | assign_expr ">>>=" assign_expr { `(setf ,$1 (lsh ,$1 (- ,$3))) } | assign_expr "&=" assign_expr { `(setf ,$1 (logand ,$1 ,$3)) } | assign_expr "^=" assign_expr { `(setf ,$1 (logxor ,$1 ,$3)) } | assign_expr "|=" assign_expr { `(setf ,$1 (logior ,$1 ,$3)) } | assign_expr '?' assign_expr ':' assign_expr {`(if ,$1 ,$3 ,$5)} /* XXX undocumented non-standard syntax */ | '[' arg_list ']' { `(vector .,(reverse $2 )) } | '[' ']' { `(vector) } ; expr: assign_expr | expr ',' assign_expr {`(progn ,$1 ,$3)} ; stmt: block | var_stmt | empty_stmt | expr_stmt | if_stmt | iter_stmt | cont_stmt | break_stmt | return_stmt | with_stmt ; block: '{' '}' { nil } | '{' stmt_list '}' { `(progn . ,(nreverse $2)) } ; stmt_list: stmt { (list $1) } | stmt_list stmt { (cons $2 $1) } ; var_stmt: VAR vardecl_list magic_semicolon { `(setq . ,(nreverse $2)) } ; vardecl_list: vardecl | vardecl_list ',' vardecl { (nconc $3 $1) } ; vardecl: IDENTIFIER { (list nil $1) } | IDENTIFIER '=' assign_expr { (list $3 $1) } ; empty_stmt: ';' {nil} ; expr_stmt: expr magic_semicolon ; if_stmt: IF '(' expr ')' stmt ELSE stmt { `(if ,$3 ,$5 ,$7) } | IF '(' expr ')' stmt { `(if ,$3 ,$5) } expr_opt: /* empty */ {nil} | expr ; iter_stmt: WHILE '(' expr ')' stmt {`(while ,$3 ,$5)} | FOR '(' expr_opt ';' expr_opt ';' expr_opt ')' stmt { `(progn ,$3 (while ,$5 ,$9 ,$7)) } | FOR '(' VAR vardecl_list ';' expr_opt ';' expr_opt ')' stmt { `(progn (setq . ,(nreverse $4)) (while ,$6 ,$10 ,$8)) } | FOR '(' lhs_expr IN expr ')' stmt | FOR '(' VAR IDENTIFIER IN expr ')' stmt { `(mapcar (function (lambda (,$4) ,$8)) ,$6) } | FOR '(' VAR IDENTIFIER '=' assign_expr IN expr ')' stmt ; cont_stmt: CONTINUE magic_semicolon ; break_stmt: BREAK magic_semicolon ; return_stmt: RETURN {(setq ecma-newline-prohibitted t)} expr_opt magic_semicolon ; with_stmt: WITH '(' expr ')' stmt ; magic_semicolon: ';' | '\n' | error { (or ecma-newline-found (error "Parse Error")) } ; func_decl: FUNCTION IDENTIFIER '(' formals_opt ')' block {`(defun ,$2 ,$4 ,$6)} ; formals_opt: /* empty */ {nil} | formals {(nreverse $1)} ; formals: IDENTIFIER {(list $1)} | formals ',' IDENTIFIER {(cons $3 $1)} ; elems: elem {(list $1)} | elems elem {(cons $2 $1)} ; elem: stmt | func_decl ; program: elems {`(progn .,(nreverse $1))} ; %%