diff --git a/src/language.yacc b/src/language.yacc
new file mode 100644
index 0000000000000000000000000000000000000000..c473d5bc0d47e3968e124212fbdf0c02e6147bc1
--- /dev/null
+++ b/src/language.yacc
@@ -0,0 +1,1203 @@
+/*\
+||| This file a part of Pike, and is copyright by Fredrik Hubinette
+||| Pike is distributed as GPL (General Public License)
+||| See the files COPYING and DISCLAIMER for more information.
+\*/
+%pure_parser
+
+/*
+ * These values are used by the stack machine, and can not be directly
+ * called from Pike.
+ */
+%token F_ADD_256 F_ADD_512 F_ADD_768 F_ADD_1024 F_ADD_256X
+%token F_PREFIX_256 F_PREFIX_512 F_PREFIX_768 F_PREFIX_1024
+%token F_PREFIX_CHARX256 F_PREFIX_WORDX256 F_PREFIX_24BITX256
+%token F_POP_VALUE F_POP_N_ELEMS F_MARK F_MARK2
+%token F_CALL_LFUN F_CALL_LFUN_AND_POP
+
+%token F_BRANCH F_BRANCH_WHEN_ZERO F_BRANCH_WHEN_NON_ZERO
+%token F_BRANCH_WHEN_LT F_BRANCH_WHEN_GT
+%token F_BRANCH_WHEN_LE F_BRANCH_WHEN_GE
+%token F_BRANCH_WHEN_EQ F_BRANCH_WHEN_NE
+%token F_INC_LOOP F_DEC_LOOP
+%token F_INC_NEQ_LOOP F_DEC_NEQ_LOOP
+
+%token F_INDEX F_INDIRECT F_STRING_INDEX F_LOCAL_INDEX
+%token F_POS_INT_INDEX F_NEG_INT_INDEX
+%token F_LTOSVAL F_LTOSVAL2
+%token F_PUSH_ARRAY 
+%token F_RANGE F_COPY_VALUE
+
+/*
+ * Basic value pushing
+ */
+%token F_LFUN F_GLOBAL F_LOCAL
+%token F_GLOBAL_LVALUE F_LOCAL_LVALUE
+%token F_CLEAR_LOCAL
+%token F_CONSTANT F_FLOAT F_STRING
+%token F_NUMBER F_NEG_NUMBER F_CONST_1 F_CONST0 F_CONST1 F_BIGNUM
+/*
+ * These are the predefined functions that can be accessed from Pike.
+ */
+
+%token F_INC F_DEC F_POST_INC F_POST_DEC F_INC_AND_POP F_DEC_AND_POP
+%token F_INC_LOCAL F_INC_LOCAL_AND_POP F_POST_INC_LOCAL
+%token F_DEC_LOCAL F_DEC_LOCAL_AND_POP F_POST_DEC_LOCAL
+%token F_RETURN F_DUMB_RETURN F_RETURN_0 F_THROW_ZERO
+
+%token F_ASSIGN F_ASSIGN_AND_POP
+%token F_ASSIGN_LOCAL F_ASSIGN_LOCAL_AND_POP
+%token F_ASSIGN_GLOBAL F_ASSIGN_GLOBAL_AND_POP
+%token F_ADD F_SUBTRACT
+%token F_MULTIPLY F_DIVIDE F_MOD
+
+%token F_LT F_GT F_EQ F_GE F_LE F_NE
+%token F_NEGATE F_NOT F_COMPL
+%token F_AND F_OR F_XOR
+%token F_LSH F_RSH
+%token F_LAND F_LOR
+
+%token F_SWITCH F_SSCANF F_CATCH
+%token F_CAST
+%token F_FOREACH
+
+%token F_SIZEOF F_SIZEOF_LOCAL
+
+/*
+ * These are token values that needn't have an associated code for the
+ * compiled file
+ */
+
+%token F_MAX_OPCODE
+%token F_ADD_EQ
+%token F_AND_EQ
+%token F_APPLY
+%token F_ARG_LIST
+%token F_ARRAY_ID
+%token F_ARROW
+%token F_BREAK
+%token F_CASE
+%token F_CLASS
+%token F_COLON_COLON
+%token F_COMMA
+%token F_CONTINUE 
+%token F_DEFAULT
+%token F_DIV_EQ
+%token F_DO
+%token F_DOT_DOT
+%token F_DOT_DOT_DOT
+%token F_PREDEF
+%token F_EFUN_CALL
+%token F_ELSE
+%token F_FLOAT_ID
+%token F_FOR
+%token F_FUNCTION_ID
+%token F_GAUGE
+%token F_IDENTIFIER
+%token F_IF
+%token F_INHERIT
+%token F_INLINE
+%token F_INT_ID
+%token F_LAMBDA
+%token F_MULTISET_ID
+%token F_MULTISET_END
+%token F_MULTISET_START
+%token F_LOCAL
+%token F_LSH_EQ
+%token F_LVALUE_LIST
+%token F_MAPPING_ID
+%token F_MIXED_ID
+%token F_MOD_EQ
+%token F_MULT_EQ
+%token F_NO_MASK
+%token F_OBJECT_ID
+%token F_OR_EQ
+%token F_PRIVATE
+%token F_PROGRAM_ID
+%token F_PROTECTED
+%token F_PUBLIC
+%token F_RSH_EQ
+%token F_STATIC
+%token F_STATUS
+%token F_STRING_ID
+%token F_SUBSCRIPT
+%token F_SUB_EQ
+%token F_TYPEOF
+%token F_VAL_LVAL
+%token F_VARARGS 
+%token F_VOID_ID
+%token F_WHILE
+%token F_XOR_EQ
+
+%token F_ALIGN
+%token F_POINTER
+%token F_LABEL
+
+%token F_MAX_INSTR
+
+%right '='
+%right '?'
+%left F_LOR
+%left F_LAND
+%left '|'
+%left '^'
+%left '&'
+%left F_EQ F_NE
+%left '>' F_GE '<' F_LE  /* nonassoc? */
+%left F_LSH F_RSH
+%left '+' '-'
+%left '*' '%' '/'
+%right F_NOT '~'
+%nonassoc F_INC F_DEC
+
+
+%{
+/* This is the grammar definition of Pike. */
+
+#include "global.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#include "interpret.h"
+#include "array.h"
+#include "object.h"
+#include "stralloc.h"
+#include "las.h"
+#include "interpret.h"
+#include "lex.h"
+#include "program.h"
+#include "pike_types.h"
+#include "constants.h"
+#include "macros.h"
+#include "error.h"
+#include "docode.h"
+
+#define YYMAXDEPTH	600
+
+static void push_locals();
+static void pop_locals();
+void free_all_local_names();
+void add_local_name(struct pike_string *,struct pike_string *);
+
+/*
+ * The names and types of arguments and auto variables.
+ */
+struct locals *local_variables;
+
+static int varargs;
+static INT32  current_modifiers;
+
+void fix_comp_stack(int sp)
+{
+  if(comp_stackp>sp)
+  {
+    yyerror("Compiler stack fixed.");
+    comp_stackp=sp;
+  }else if(comp_stackp<sp){
+    fatal("Compiler stack frame underflow.");
+  }
+}
+
+%}
+%union
+{
+  int number;
+  FLOAT_TYPE fnum;
+  unsigned int address;		/* Address of an instruction */
+  struct pike_string *string;
+  char *str;
+  unsigned short type;
+  struct node_s *n;
+  struct efun *efun;
+}
+
+%type <fnum> F_FLOAT
+%type <number> modifiers modifier optional_dot_dot_dot
+%type <number> assign F_NUMBER F_LOCAL arguments arguments2
+%type <number> optional_stars modifier_list
+%type <string> F_IDENTIFIER F_STRING string_constant low_string
+%type <string> optional_identifier cast simple_type
+%type <string> optional_rename_inherit
+
+%type <number> F_ARRAY_ID F_BREAK F_CASE F_CATCH F_CONTINUE F_DEFAULT F_DO
+%type <number> F_PREDEF F_ELSE F_FLOAT_ID F_FOR F_FOREACH F_FUNCTION_ID F_GAUGE
+%type <number> F_IF F_INHERIT F_INLINE F_INT_ID F_LAMBDA F_MULTISET_ID F_MAPPING_ID
+%type <number> F_MIXED_ID F_NO_MASK F_OBJECT_ID F_PRIVATE F_PROGRAM_ID
+%type <number> F_PROTECTED F_PUBLIC F_RETURN F_SSCANF F_STATIC
+%type <number> F_STRING_ID F_SWITCH F_VARARGS F_VOID_ID F_WHILE
+
+/* The following symbos return type information */
+
+%type <n> string expr01 expr00 comma_expr comma_expr_or_zero
+%type <n> expr2 expr1 expr3 expr0 expr4 catch lvalue_list
+%type <n> lambda for_expr block  assoc_pair new_local_name
+%type <n> expr_list2 m_expr_list m_expr_list2 statement gauge sscanf
+%type <n> for do cond optional_else_part while statements
+%type <n> local_name_list class catch_arg comma_expr_or_maxint
+%type <n> unused2 foreach unused switch case return expr_list default
+%type <n> continue break block_or_semi typeof
+%%
+
+all: program;
+
+program: program def optional_semi_colon
+       |  /* empty */ ;
+
+optional_semi_colon: /* empty */
+                   | ';' { yyerror("Extra ';'. Ignored."); };
+
+string_constant: low_string
+	   | string_constant '+' low_string
+           {
+             $$=add_shared_strings($1,$3);
+	     free_string($1);
+	     free_string($3);
+           }
+           ;
+
+optional_rename_inherit: ':' F_IDENTIFIER { $$=$2; }
+                       | { $$=0; }
+                       ;
+          
+inheritance: modifiers F_INHERIT string_constant optional_rename_inherit ';'
+	{
+	  simple_do_inherit($3,$1,$4);
+	};
+
+block_or_semi: block { $$ = mknode(F_ARG_LIST,$1,mknode(F_RETURN,mkintnode(0),0)); }
+             | ';' { $$ = NULL;}
+             ;
+
+
+type_or_error: simple_type
+             {
+                if(local_variables->current_type) free_string(local_variables->current_type); 
+                local_variables->current_type=$1;
+             }
+             | /* empty */
+             {
+	       yyerror("Missing type.");
+	       copy_shared_string(local_variables->current_type,
+				  mixed_type_string);
+	     }
+  
+
+def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')'
+   {
+     int e;
+     /* construct the function type */
+     push_finished_type(local_variables->current_type);
+     while($3--) push_type(T_ARRAY);
+
+     if(local_variables->current_return_type)
+       free_string(local_variables->current_return_type);
+     local_variables->current_return_type=pop_type();
+
+     push_finished_type(local_variables->current_return_type);
+
+     e=$6-1;
+     if(varargs)
+     {
+       push_finished_type(local_variables->variable[e].type);
+       e--;
+       varargs=0;
+       pop_type_stack();
+     }else{
+       push_type(T_VOID);
+     }
+     push_type(T_MANY);
+     for(; e>=0; e--)
+     {
+       push_finished_type(local_variables->variable[e].type);
+       if($1 & ID_VARARGS)
+       {
+	 push_type(T_VOID);
+	 push_type(T_OR);
+       }
+     }
+     push_type(T_FUNCTION);
+
+     $<string>$=pop_type();
+     define_function($4,
+		     $<string>$,
+		     $1,
+		     IDENTIFIER_PIKE_FUNCTION,
+		     0);
+   }
+   block_or_semi
+   {
+     int e;
+     if($9)
+     {
+       union idptr tmp;
+       int args, vargs;
+       for(e=0; e<$6; e++)
+       {
+	 if(!local_variables->variable[e].name ||
+	    !local_variables->variable[e].name->len)
+	 {
+	   my_yyerror("Missing name for argument %d",e);
+	 }
+       }
+
+       tmp.offset=PC;
+       args=count_arguments($<string>8);
+       if(args < 0) 
+       {
+	 args=~args;
+	 vargs=IDENTIFIER_VARARGS;
+       }else{
+	 vargs=0;
+       }
+       ins_byte(local_variables->max_number_of_locals, A_PROGRAM);
+       ins_byte(args, A_PROGRAM);
+       dooptcode($4, $9, $6);
+
+       define_function($4,
+		       $<string>8,
+		       $1,
+		       IDENTIFIER_PIKE_FUNCTION | vargs,
+		       &tmp);
+     }
+     if(local_variables->current_return_type)
+     {
+       free_string(local_variables->current_return_type);
+       local_variables->current_return_type=0;
+     }
+     free_all_local_names();
+     free_string($4);
+     free_string($<string>8);
+   }
+   | modifiers type_or_error name_list ';' {}
+   | inheritance {}
+   | error 
+   {
+     reset_type_stack();
+     if(num_parse_error>5) YYACCEPT;
+   } ;
+
+
+optional_dot_dot_dot: F_DOT_DOT_DOT { $$=1; }
+                    | /* empty */ { $$=0; }
+                    ;
+
+optional_identifier: F_IDENTIFIER
+                   | /* empty */ { $$=make_shared_string(""); }
+                   ;
+
+
+new_arg_name: type optional_dot_dot_dot optional_identifier
+            {
+              if(varargs) yyerror("Can't define more arguments after ...");
+
+	      if($2)
+	      {
+		push_type(T_ARRAY);
+		varargs=1;
+	      }
+	      if(islocal($3) >= 0)
+		my_yyerror("Variable '%s' appear twice in argument list.",
+			   $3->str);
+
+	      add_local_name($3, pop_type());
+            };
+
+arguments: /* empty */ optional_comma { $$=0; }
+          | arguments2 optional_comma { $$=$1; }
+          ;
+
+arguments2: new_arg_name { $$ = 1; }
+          | arguments2 ',' new_arg_name { $$ = $1 + 1; }
+          ;
+
+modifier: F_NO_MASK    { $$ = ID_NOMASK; }
+        | F_STATIC     { $$ = ID_STATIC; }
+	| F_PRIVATE    { $$ = ID_PRIVATE; }
+	| F_PUBLIC     { $$ = ID_PUBLIC; }
+	| F_VARARGS    { $$ = ID_VARARGS; }
+	| F_PROTECTED  { $$ = ID_PROTECTED; }
+	| F_INLINE     { $$ = ID_INLINE | ID_NOMASK; }
+        ;
+
+modifiers: modifier_list { $$=current_modifiers=$1; }
+
+modifier_list: /* empty */ { $$ = 0; }
+	 | modifier modifier_list
+         {
+            $$ = $1 | $2;
+         }
+         ;
+
+optional_stars: optional_stars '*' { $$=$1 + 1; }
+              | /* empty */ { $$=0; }
+              ;
+
+cast: '(' type ')' { $$=pop_type(); } ;
+
+type: type '*' { push_type(T_ARRAY); }
+    | type2
+    ;
+
+simple_type: type2 { $$=pop_type(); }
+
+type2: type2 '|' type3 { push_type(T_OR); }
+     | type3
+     ;
+
+type3: F_INT_ID      { push_type(T_INT); }
+     | F_FLOAT_ID    { push_type(T_FLOAT); }
+     | F_STRING_ID   { push_type(T_STRING); }
+     | F_OBJECT_ID   { push_type(T_OBJECT); }
+     | F_PROGRAM_ID  { push_type(T_PROGRAM); }
+     | F_VOID_ID     { push_type(T_VOID); }
+     | F_MIXED_ID    { push_type(T_MIXED); }
+     | F_MAPPING_ID opt_mapping_type { push_type(T_MAPPING); }
+     | F_ARRAY_ID opt_array_type { push_type(T_ARRAY); }
+     | F_MULTISET_ID opt_array_type { push_type(T_MULTISET); }
+     | F_FUNCTION_ID opt_function_type { push_type(T_FUNCTION); }
+     ;
+
+opt_function_type: '('
+                 {
+                   type_stack_mark();
+                   type_stack_mark();
+		 }
+ 		 function_type_list
+                 optional_dot_dot_dot
+                 ':'
+                 {
+                   if ($4)
+		   {
+                     push_type(T_MANY);
+                     type_stack_reverse();
+                   }else{
+                     type_stack_reverse();
+		     push_type(T_MANY);
+		     push_type(T_VOID);
+		   }
+                   type_stack_mark();
+		 }
+                 type ')'
+                 {
+		   type_stack_reverse();
+		   type_stack_reverse();
+		 }
+                 | {
+                   push_type(T_MIXED);
+                   push_type(T_MIXED);
+                   push_type(T_MANY);
+                 };
+
+function_type_list: /* Empty */ optional_comma
+                  | function_type_list2 optional_comma
+                  ;
+
+function_type_list2: type 
+                  | function_type_list2 ','
+                  {
+                    type_stack_reverse();
+                    type_stack_mark();
+                  }
+	          type
+                  ;
+
+opt_array_type: '(' type ')'
+              |  { push_type(T_MIXED); }
+              ;
+
+opt_mapping_type: '('
+                { 
+                  type_stack_mark();
+                  type_stack_mark();
+                }
+                type ':'
+                { 
+                  type_stack_reverse();
+                  type_stack_mark();
+                }
+                type
+                { 
+                  type_stack_reverse();
+                  type_stack_reverse();
+                }
+                ')'
+                | {
+                    push_type(T_MIXED);
+                    push_type(T_MIXED);
+		  }
+                ;
+
+
+
+name_list: new_name
+	 | name_list ',' new_name;
+
+new_name: optional_stars F_IDENTIFIER
+	{
+	  struct pike_string *type;
+	  push_finished_type(local_variables->current_type);
+	  while($1--) push_type(T_ARRAY);
+	  type=pop_type();
+          define_variable($2, type, current_modifiers);
+	  free_string(type);
+	  free_string($2);
+	}
+        | optional_stars F_IDENTIFIER '='
+        {
+	  struct pike_string *type;
+	  push_finished_type(local_variables->current_type);
+	  while($1--) push_type(T_ARRAY);
+	  type=pop_type();
+          $<number>$=define_variable($2, type, current_modifiers);
+	  free_string(type);
+        }
+        expr0
+	{
+          init_node=mknode(F_ARG_LIST,init_node,
+		mkcastnode(void_type_string, mknode(F_ASSIGN,$5,mkidentifiernode($<number>4))));
+          free_string($2);
+	} ;
+
+
+new_local_name: optional_stars F_IDENTIFIER
+                {
+		  push_finished_type(local_variables->current_type);
+		  while($1--) push_type(T_ARRAY);
+                  add_local_name($2, pop_type());
+                  $$=mkcastnode(void_type_string,
+				mknode(F_ASSIGN,mkintnode(0),
+				       mklocalnode(islocal($2))));
+                }
+              | optional_stars F_IDENTIFIER '=' expr0
+                {
+		  push_finished_type(local_variables->current_type);
+		  while($1--) push_type(T_ARRAY);
+                  add_local_name($2, pop_type());
+                  $$=mkcastnode(void_type_string,
+				mknode(F_ASSIGN,$4,
+				       mklocalnode(islocal($2))));
+                  
+                };
+
+
+block:'{'
+     {
+       $<number>$=local_variables->current_number_of_locals;
+     } 
+     statements
+     '}'
+     {
+       while(local_variables->current_number_of_locals > $<number>2)
+       {
+	 int e;
+	 e=--(local_variables->current_number_of_locals);
+	 free_string(local_variables->variable[e].name);
+	 free_string(local_variables->variable[e].type);
+       }
+       $$=$3;
+     } ;
+
+local_name_list: new_local_name
+               | local_name_list ',' new_local_name
+	       {
+		 $$=mknode(F_ARG_LIST,$1,$3);
+	       }
+               ;
+
+statements: { $$=0; }
+          | statements statement
+            {
+              $$=mknode(F_ARG_LIST,$1,mkcastnode(void_type_string,$2));
+            }
+          ;
+
+statement: unused2 ';' { $$=$1; }
+         | simple_type
+         {
+	   if(local_variables->current_type) free_string(local_variables->current_type);
+	   local_variables->current_type=$1;
+	 } local_name_list ';' { $$=$3; }
+         | cond
+         | while
+         | do
+         | for
+         | switch
+         | case
+         | default
+         | return ';'
+	 | block {}
+         | foreach
+         | break ';'
+         | continue ';'
+         | error ';' { $$=0; }
+  	 | ';' { $$=0; } 
+         ;
+
+
+break: F_BREAK { $$=mknode(F_BREAK,0,0); } ;
+default: F_DEFAULT ':'  { $$=mknode(F_DEFAULT,0,0); } ;
+continue: F_CONTINUE { $$=mknode(F_CONTINUE,0,0); } ;
+
+lambda: F_LAMBDA
+	{
+	  push_locals();
+	  $<number>$=comp_stackp;
+
+	  if(local_variables->current_return_type)
+	    free_string(local_variables->current_return_type);
+	  copy_shared_string(local_variables->current_return_type,any_type_string);
+	}
+       '(' arguments ')' block
+        {
+          struct pike_string *type;
+	  char buf[40];
+	  int f,e,args,vargs;
+	  union idptr func;
+	  struct pike_string *name;
+
+	  setup_fake_program();
+	  fix_comp_stack($<number>2);
+
+	  push_type(T_MIXED);
+
+	  e=$4-1;
+	  if(varargs)
+	  {
+	    push_finished_type(local_variables->variable[e].type);
+	    e--;
+	    varargs=0;
+	    pop_type_stack();
+	  }else{
+	    push_type(T_VOID);
+	  }
+	  push_type(T_MANY);
+	  for(; e>=0; e--)
+	    push_finished_type(local_variables->variable[e].type);
+
+	  push_type(T_FUNCTION);
+
+	  type=pop_type();
+	  func.offset=PC;
+
+	  args=count_arguments(type);
+	  if(args < 0) 
+	  {
+	    args=~args;
+	    vargs=IDENTIFIER_VARARGS;
+	  }else{
+	    vargs=0;
+	  }
+	  ins_byte(local_variables->max_number_of_locals, A_PROGRAM);
+	  ins_byte(args, A_PROGRAM);
+	  
+	  sprintf(buf,"__lambda_%ld",
+		  (long)fake_program.num_identifier_references);
+	  name=make_shared_string(buf);
+          dooptcode(name,mknode(F_ARG_LIST,$6,mknode(F_RETURN,mkintnode(0),0)),$4);
+	  f=define_function(name,
+			    type,
+			    0,
+			    IDENTIFIER_PIKE_FUNCTION | vargs,
+			    &func);
+	  free_string(name);
+	  free_string(type);
+	  pop_locals();
+          $$=mkidentifiernode(f);
+	} ;
+
+class: F_CLASS '{'
+       {
+         start_new_program();
+       }
+       program
+       '}'
+       {
+         struct svalue s;
+         s.u.program=end_program();
+	 if(!s.u.program)
+	 {
+	   yyerror("Class definition failed.");
+           s.type=T_INT;
+           s.subtype=0;
+	 } else {
+           s.type=T_PROGRAM;
+           s.subtype=0;
+         }
+	 $$=mksvaluenode(&s);
+         free_svalue(&s);
+       } ;
+
+cond: F_IF '(' comma_expr ')' 
+      statement
+      optional_else_part
+      {
+	$$=mknode('?',$3,mknode(':',$5,$6));
+	$$->line_number=$1;
+        $$=mkcastnode(void_type_string,$$);
+	$$->line_number=$1;
+      }
+    ;
+
+optional_else_part: { $$=0; }
+    | F_ELSE statement { $$=$2; }
+    ;      
+
+foreach: F_FOREACH '(' expr0 ',' expr4 ')'
+         statement
+	 {
+           $$=mknode(F_FOREACH,mknode(F_VAL_LVAL,$3,$5),$7);
+	   $$->line_number=$1;
+	 } ;
+
+do: F_DO statement F_WHILE '(' comma_expr ')' ';'
+    {
+      $$=mknode(F_DO,$2,$5);
+      $$->line_number=$1;
+    } ;
+
+
+for: F_FOR '(' unused  ';' for_expr ';' unused ')'
+     statement
+     {
+       int i=current_line;
+       current_line=$1;
+       $$=mknode(F_ARG_LIST,mkcastnode(void_type_string,$3),mknode(F_FOR,$5,mknode(':',$9,$7)));
+       current_line=i;
+     } ;
+
+
+while:  F_WHILE '(' comma_expr ')'
+        statement
+	{
+	  int i=current_line;
+	  current_line=$1;
+	  $$=mknode(F_FOR,$3,mknode(':',$5,NULL));
+	  current_line=i;
+        } ;
+
+for_expr: /* EMPTY */ { $$=mkintnode(1); }
+        | comma_expr;
+
+switch:	F_SWITCH '(' comma_expr ')'
+        statement
+        {
+          $$=mknode(F_SWITCH,$3,$5);
+	  $$->line_number=$1;
+        } ;
+
+case: F_CASE comma_expr ':'
+    {
+      $$=mknode(F_CASE,$2,0);
+    }
+    | F_CASE comma_expr F_DOT_DOT comma_expr ':'
+    {
+      $$=mknode(F_CASE,$2,$4);
+    }
+    ;
+
+return: F_RETURN
+	{
+	  if(!match_types(local_variables->current_return_type,
+			  void_type_string))
+	  {
+	    yyerror("Must return a value for a non-void function.");
+	  }
+          $$=mknode(F_RETURN,mkintnode(0),0);
+	}
+      | F_RETURN comma_expr
+	{
+          $$=mknode(F_RETURN,$2,0);
+	};
+	
+unused: { $$=0; }
+      | unused2
+      ;
+
+unused2: comma_expr
+       {
+         $$=mkcastnode(void_type_string,$1);
+       }
+       ;
+
+comma_expr: expr0
+          | unused2 ',' expr0
+          {
+	    $$ = mknode(F_ARG_LIST,mkcastnode(void_type_string,$1),$3); 
+	  }
+          ;
+
+expr00: expr0
+      | '@' expr0
+      {
+	$$=mknode(F_PUSH_ARRAY,$2,0);
+      };
+
+expr0: expr01
+     | expr4 '=' expr0
+       {
+         $$=mknode(F_ASSIGN,$3,$1);
+       }
+     | expr4 assign expr0
+       {
+	 $$=mknode($2,$1,$3);
+       }
+     | error assign expr01
+       {
+          $$=0;
+       };
+
+expr01: expr1 { $$ = $1; }
+     | expr1 '?' expr01 ':' expr01
+	{
+          $$=mknode('?',$1,mknode(':',$3,$5));
+	};
+
+assign: F_AND_EQ { $$=F_AND_EQ; }
+      | F_OR_EQ  { $$=F_OR_EQ; }
+      | F_XOR_EQ { $$=F_XOR_EQ; }
+      | F_LSH_EQ { $$=F_LSH_EQ; }
+      | F_RSH_EQ { $$=F_RSH_EQ; }
+      | F_ADD_EQ { $$=F_ADD_EQ; }
+      | F_SUB_EQ { $$=F_SUB_EQ; }
+      | F_MULT_EQ{ $$=F_MULT_EQ; }
+      | F_MOD_EQ { $$=F_MOD_EQ; }
+      | F_DIV_EQ { $$=F_DIV_EQ; }
+      ;
+
+optional_comma: | ',' ;
+
+expr_list: { $$=0; }
+         | expr_list2 optional_comma { $$=$1; }
+         ;
+         
+
+expr_list2: expr00
+          | expr_list2 ',' expr00 { $$=mknode(F_ARG_LIST,$1,$3); }
+          ;
+
+m_expr_list: { $$=0; }
+           | m_expr_list2 optional_comma { $$=$1; }
+           ;
+
+m_expr_list2: assoc_pair
+            | m_expr_list2 ',' assoc_pair { $$=mknode(F_ARG_LIST,$1,$3); }
+            ;
+
+assoc_pair:  expr0 ':' expr1
+             {
+               $$=mknode(F_ARG_LIST,$1,$3);
+             } ;
+
+expr1: expr2
+     | expr1 F_LOR expr1  { $$=mknode(F_LOR,$1,$3); }
+     | expr1 F_LAND expr1 { $$=mknode(F_LAND,$1,$3); }
+     | expr1 '|' expr1    { $$=mkopernode("`|",$1,$3); }
+     | expr1 '^' expr1    { $$=mkopernode("`^",$1,$3); }
+     | expr1 '&' expr1    { $$=mkopernode("`&",$1,$3); }
+     | expr1 F_EQ expr1   { $$=mkopernode("`==",$1,$3); }
+     | expr1 F_NE expr1   { $$=mkopernode("`!=",$1,$3); }
+     | expr1 '>' expr1    { $$=mkopernode("`>",$1,$3); }
+     | expr1 F_GE expr1   { $$=mkopernode("`>=",$1,$3); }
+     | expr1 '<' expr1    { $$=mkopernode("`<",$1,$3); }
+     | expr1 F_LE expr1   { $$=mkopernode("`<=",$1,$3); }
+     | expr1 F_LSH expr1  { $$=mkopernode("`<<",$1,$3); }
+     | expr1 F_RSH expr1  { $$=mkopernode("`>>",$1,$3); }
+     | expr1 '+' expr1    { $$=mkopernode("`+",$1,$3); }
+     | expr1 '-' expr1    { $$=mkopernode("`-",$1,$3); }
+     | expr1 '*' expr1    { $$=mkopernode("`*",$1,$3); }
+     | expr1 '%' expr1    { $$=mkopernode("`%",$1,$3); }
+     | expr1 '/' expr1    { $$=mkopernode("`/",$1,$3); }
+     ;
+
+expr2: expr3
+     | cast expr2
+     {
+       $$=mkcastnode($1,$2);
+       free_string($1);
+     }
+     | F_INC expr4       { $$=mknode(F_INC,$2,0); }
+     | F_DEC expr4       { $$=mknode(F_DEC,$2,0); }
+     | F_NOT expr2        { $$=mkopernode("`!",$2,0); }
+     | '~' expr2          { $$=mkopernode("`~",$2,0); }
+     | '-' expr2          { $$=mkopernode("`-",$2,0); }
+     ;
+
+expr3: expr4
+     | expr4 F_INC       { $$=mknode(F_POST_INC,$1,0); }
+     | expr4 F_DEC       { $$=mknode(F_POST_DEC,$1,0); }
+     ;
+
+expr4: string
+     | F_NUMBER { $$=mkintnode($1); }
+     | F_FLOAT { $$=mkfloatnode($1); }
+     | catch
+     | gauge
+     | typeof
+     | sscanf
+     | lambda
+     | class
+     | F_IDENTIFIER
+     {
+       int i;
+       struct efun *f;
+       if((i=islocal($1))>=0)
+       {
+         $$=mklocalnode(i);
+       }else if((i=isidentifier($1))>=0){
+         $$=mkidentifiernode(i);
+       }else if((f=lookup_efun($1))){
+	 $$=mkconstantsvaluenode(&f->function);
+       }else{
+	 my_yyerror("'%s' undefined.",$1->str);
+         $$=0;
+       }
+       free_string($1);
+     }
+     | F_PREDEF F_COLON_COLON F_IDENTIFIER
+     {
+       struct efun *f;
+       f=lookup_efun($3);
+       if(!f)
+       {
+	 my_yyerror("Unknown efun: %s.",$3->str);
+	 $$=mkintnode(0);
+       }else{
+	 $$=mksvaluenode(&f->function);
+       }
+       free_string($3);
+     }
+     | expr4 '(' expr_list ')' { $$=mkapplynode($1,$3); }
+     | expr4 '[' expr0 ']' { $$=mknode(F_INDEX,$1,$3); }
+     | expr4 '['  comma_expr_or_zero F_DOT_DOT comma_expr_or_maxint ']'
+     {
+       $$=mknode(F_RANGE,$1,mknode(F_ARG_LIST,$3,$5));
+     }
+     | '(' comma_expr ')' { $$=$2; }
+     | '(' '{' expr_list '}' ')'
+       { $$=mkefuncallnode("aggregate",$3); }
+     | '(' '[' m_expr_list ']' ')'
+       { $$=mkefuncallnode("aggregate_mapping",$3); };
+     | F_MULTISET_START expr_list F_MULTISET_END
+       { $$=mkefuncallnode("aggregate_multiset",$2); }
+     | expr4 F_ARROW F_IDENTIFIER
+     {
+       $$=mknode(F_INDEX,$1,mkstrnode($3));
+       free_string($3);
+     }
+     | F_IDENTIFIER F_COLON_COLON F_IDENTIFIER
+     {
+       int f;
+       struct reference *idp;
+
+       setup_fake_program();
+       f=reference_inherited_identifier($1,$3);
+       idp=fake_program.identifier_references+f;
+       if (f<0 || ID_FROM_PTR(&fake_program,idp)->func.offset == -1)
+       {
+	 my_yyerror("Undefined identifier %s::%s", $1->str,$3->str);
+	 $$=mkintnode(0);
+       } else {
+	 $$=mkidentifiernode(f);
+       }
+
+       free_string($1);
+       free_string($3);
+     }
+     | F_COLON_COLON F_IDENTIFIER
+     {
+       int e,i;
+
+       $$=0;
+       setup_fake_program();
+       for(e=1;e<(int)fake_program.num_inherits;e++)
+       {
+	 if(fake_program.inherits[e].inherit_level!=1) continue;
+	 i=low_reference_inherited_identifier(e,$2);
+	 if(i==-1) continue;
+	 if($$)
+	 {
+	   $$=mknode(F_ARG_LIST,$$,mkidentifiernode(i));
+	 }else{
+	   $$=mkidentifiernode(i);
+	 }
+       }
+       if(!$$)
+       {
+	 $$=mkintnode(0);
+       }else{
+	 if($$->token==F_ARG_LIST) $$=mkefuncallnode("aggregate",$$);
+       }
+       free_string($2);
+     }
+     ;
+
+comma_expr_or_zero: /* empty */ { $$=mkintnode(0); }
+                  | comma_expr
+                  ;
+
+comma_expr_or_maxint: /* empty */ { $$=mkintnode(0x7fffffff); }
+                    | comma_expr
+                    ;
+
+gauge: F_GAUGE catch_arg
+  {
+    $$=mkopernode("`-",
+		  mkopernode("`-",
+			     mknode(F_INDEX,mkefuncallnode("rusage",0),
+				    mkintnode(GAUGE_RUSAGE_INDEX)),
+			     mknode(F_ARG_LIST,$2,
+				    mknode(F_INDEX,mkefuncallnode("rusage",0),
+					   mkintnode(GAUGE_RUSAGE_INDEX)))),0);
+  } ;
+
+typeof: F_TYPEOF '(' expr0 ')'
+      {
+	node *tmp;
+	tmp=mknode(F_ARG_LIST,$3,0);
+        $$=mkstrnode(describe_type($3->type));
+        free_node(tmp);
+      } ;
+
+catch_arg: '(' comma_expr ')'  { $$=$2; }
+         | block
+         ; 
+
+catch: F_CATCH catch_arg
+     {
+       $$=mknode(F_CATCH,$2,NULL);
+     } ;
+
+sscanf: F_SSCANF '(' expr0 ',' expr0 lvalue_list ')'
+      {
+        $$=mknode(F_SSCANF,mknode(F_ARG_LIST,$3,$5),$6);
+      }
+
+
+lvalue_list: /* empty */ { $$ = 0; }
+	   | ',' expr4 lvalue_list
+           {
+             $$ = mknode(F_LVALUE_LIST,$2,$3);
+           } ;
+
+low_string: F_STRING 
+          | low_string F_STRING
+          {
+            $$=add_shared_strings($1,$2);
+            free_string($1);
+            free_string($2);
+          }
+          ;
+
+string: low_string
+      {
+	$$=mkstrnode($1);
+	free_string($1);
+      } ;
+
+
+%%
+
+void yyerror(char *str)
+{
+  extern int num_parse_error;
+
+  if (num_parse_error > 5) return;
+  num_parse_error++;
+
+  if ( get_master() )
+  {
+    sp->type = T_STRING;
+    copy_shared_string(sp->u.string, current_file);
+    sp++;
+    sp->type = T_INT;
+    sp->u.integer = current_line;
+    sp++;
+    sp->type = T_STRING;
+    sp->u.string = make_shared_string(str);
+    sp++;
+    SAFE_APPLY_MASTER("compile_error",3);
+    pop_stack();
+  }else{
+    (void)fprintf(stderr, "%s:%ld: %s\n",
+		  current_file->str,
+		  (long)current_line,
+		  str);
+    fflush(stderr);
+  }
+}
+
+/* argument must be a shared string (no need to free it) */
+void add_local_name(struct pike_string *str,
+		    struct pike_string *type)
+{
+  if (local_variables->current_number_of_locals == MAX_LOCAL)
+  {
+    yyerror("Too many local variables");
+  }else {
+    local_variables->variable[local_variables->current_number_of_locals].type = type;
+    local_variables->variable[local_variables->current_number_of_locals].name = str;
+    local_variables->current_number_of_locals++;
+    if(local_variables->current_number_of_locals > 
+       local_variables->max_number_of_locals)
+    {
+      local_variables->max_number_of_locals=
+	local_variables->current_number_of_locals;
+    }
+  }
+}
+
+/* argument must be a shared string */
+int islocal(struct pike_string *str)
+{
+  int e;
+  for(e=local_variables->current_number_of_locals-1;e>=0;e--)
+    if(local_variables->variable[e].name==str)
+      return e;
+  return -1;
+}
+
+void free_all_local_names()
+{
+  int e;
+
+  for (e=0; e<local_variables->current_number_of_locals; e++)
+  {
+    if(local_variables->variable[e].name)
+    {
+      free_string(local_variables->variable[e].name);
+      free_string(local_variables->variable[e].type);
+    }
+    local_variables->variable[e].name=0;
+    local_variables->variable[e].type=0;
+  }
+  local_variables->current_number_of_locals = 0;
+  local_variables->max_number_of_locals = 0;
+}
+
+static void push_locals()
+{
+  struct locals *l;
+  l=ALLOC_STRUCT(locals);
+  l->current_type=0;
+  l->current_return_type=0;
+  l->next=local_variables;
+  l->current_number_of_locals=0;
+  l->max_number_of_locals=0;
+  local_variables=l;
+}
+
+static void pop_locals()
+{
+  struct locals *l;
+  free_all_local_names();
+  l=local_variables->next;
+  if(local_variables->current_type)
+    free_string(local_variables->current_type);
+  if(local_variables->current_return_type)
+    free_string(local_variables->current_return_type);
+  free((char *)local_variables);
+
+  local_variables=l;
+  /* insert check if ( local->next == parent locals ) here */
+}