/*
    Copyright 2001 (c) by Claudio Jeker,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.

    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.

    For further information, please visit http://www.tik.ee.ethz.ch/~topsy

    This software is provided under the terms of the GNU General Public 
    Licence. A full copy of the GNU GPL is provided in the file COPYING 
    found in the development root of Topsy.
*/
/*
	
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/VMemory/Attic/debug.y,v $
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2922 $
    Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $  by: $Author: baderma $

*/
%{

#include <sys/types.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <err.h>
#include <limits.h>

#include "vm.h"
#include "vm_region.h"
#include "vm_object.h"
#include "vm_anon.h"
#include "doubleq.h"

static FILE *fin = NULL;
static int lineno = 1;
static int errors = 0;
static int debug = 0;

struct argument {
	union {
		unsigned int i;
		struct vm_region_desc* region;
		struct vm_map* map;
		address_t addr;
	} v;
	int t;
};

#define ARG_UINT		0x01
#define ARG_REGION	0x02
#define ARG_VMMAP		0x03
#define ARG_ADDRESS	0x04
#define ARG_LAST		0x00

#define FUNC_ADD		0x01
#define FUNC_FREE		0x02
#define FUNC_SHARE	0x03
#define FUNC_RESIZE	0x04
#define FUNC_CHPROT	0x05
#define FUNC_GET		0x06

static int function(int f, int argc, struct argument* argv);

struct addrmap {
	address_t start;
	address_t end;
};

struct regmap {
	address_t start;
	address_t end;
	unsigned char cur;
	unsigned char max;
	unsigned short type;
};

typedef struct {
	union {
		unsigned long number;
		char *string;
		struct addrmap map;
		struct {
			int t;
			union {
				struct regmap r;
				char *s;
			} r;
		} region;
	} v;
	int lineno;
} YYSTYPE;

struct region {
	struct region* next;
	char *name;
	struct vm_region_desc map;
};
struct region *reghead = NULL;

static int	regset(char *name, struct regmap* map);
static int	regcopy(char *name, char *source);
static struct region* regget(char *name);
static void show_region(char *name, struct vm_region_desc* reg);

struct map {
	struct map* next;
	char *name;
	struct vm_map map;
};
struct map *maphead = NULL;

static int	mapset(char *name, struct addrmap* map);
static struct map* mapget(char *name);
static void show_vm_map(char *name, struct vm_map* vm_map);

#define TYPE_VMMAP 0x01
#define TYPE_REGION 0x02
#define TYPE_ALL (TYPE_VMMAP | TYPE_REGION)

%}

%token
	ADD FREE RESIZE SHARE CHMOD GET REGION MAP 
	SHOW QUIT

	OPENBRACELET CLOSEDBRACELET

	ERROR

%token <v.string> STRING
%token <v.string> ANY
%token <v.number> NUMBER

%type <v.number> address mode_code type share_type
%type <v.region> region
%type <v.map> map
%type <v.string> var dummy

%start cmd_list

%%

cmd_list
	: /* empty */
	| cmd_list cmd
	;

cmd
	: ADD var region'\n'
		{
			struct argument argv[3];
			struct vm_region_desc t;
			struct region* r;
			struct map* m;

			if ( $3.t == 1 ) {
				memset(&t, 0, sizeof(t));
				t.start = $3.r.r.start;
				t.end = $3.r.r.end;
				t.cur = $3.r.r.cur;
				t.max = $3.r.r.max;
				t.type = $3.r.r.type;
			} else {
				if ( strcasecmp($3.r.s, "ALL") == 0) {
					yyerror("'all' may not be used as variable name");
					break;
				}
				r = regget($3.r.s);
				if ( r == NULL ) {
					yyerror("no such variable %s", $3.r.s);
					break;
				}
				memcpy(&t, &r->map, sizeof(t) );
			}
			
			if ( strcasecmp($2, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			
			m = mapget($2);
			if ( m == NULL ) {
				yyerror("no such variable %s", $2);
				break;
			}
			
			argv[0].t = ARG_VMMAP;
			argv[0].v.map = &m->map;
			argv[1].t = ARG_REGION;
			argv[1].v.region = &t;
			argv[2].t = ARG_LAST;
			
			function(FUNC_ADD, 2, argv);
		}
	| GET var address var '\n'
		{
			struct argument argv[4];
			struct region* r;
			struct map* m;
			
			if ( strcasecmp($2, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			
			m = mapget($2);
			if ( m == NULL ) {
				yyerror("no such variable %s", $2);
				break;
			}
	
			if ( strcasecmp($4, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			
			r = regget($4);
			if ( r == NULL ) {
				yyerror("no such variable %s", $4);
				break;
			}
			
			argv[0].t = ARG_VMMAP;
			argv[0].v.map = &m->map;
			argv[1].t = ARG_ADDRESS;
			argv[1].v.addr = (address_t) $3;
			argv[2].t = ARG_REGION;
			argv[2].v.region = &r->map;
			argv[3].t = ARG_LAST;
			
			function(FUNC_GET, 3, argv);

		}
	| FREE var region '\n'
		{
			struct argument argv[3];
			struct vm_region_desc t;
			struct region* r;
			struct map* m;
			
			if ( $3.t == 1 ) {
				memset(&t, 0, sizeof(t));
				t.start = $3.r.r.start;
				t.end = $3.r.r.end;
				t.cur = $3.r.r.cur;
				t.max = $3.r.r.max;
			} else {
				if ( strcasecmp($3.r.s, "ALL") == 0) {
					yyerror("'all' may not be used as variable name");
					break;
				}
				r = regget($3.r.s);
				if ( r == NULL ) {
					yyerror("no such variable %s", $3.r.s);
					break;
				}
				memcpy(&t, &r->map, sizeof(t) );
			}
			
			if ( strcasecmp($2, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			
			m = mapget($2);
			if ( m == NULL ) {
				yyerror("no such variable %s", $2);
				break;
			}
			
			argv[0].t = ARG_VMMAP;
			argv[0].v.map = &m->map;
			argv[1].t = ARG_REGION;
			argv[1].v.region = &t;
			argv[2].t = ARG_LAST;
			
			function(FUNC_FREE, 2, argv);
		}
	| CHMOD var region mode_code mode_code '\n'
		{
			struct argument argv[5];
			struct vm_region_desc t;
			struct region* r;
			struct map* m;
			
			if ( $3.t == 1 ) {
				memset(&t, 0, sizeof(t));
				t.start = $3.r.r.start;
				t.end = $3.r.r.end;
				t.cur = $3.r.r.cur;
				t.max = $3.r.r.max;
			} else {
				if ( strcasecmp($3.r.s, "ALL") == 0) {
					yyerror("'all' may not be used as variable name");
					break;
				}
				r = regget($3.r.s);
				if ( r == NULL ) {
					yyerror("no such variable %s", $3.r.s);
					break;
				}
				memcpy(&t, &r->map, sizeof(t) );
			}
			
			if ( strcasecmp($2, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			
			m = mapget($2);
			if ( m == NULL ) {
				yyerror("no such variable %s", $2);
				break;
			}
			
			argv[0].t = ARG_VMMAP;
			argv[0].v.map = &m->map;
			argv[1].t = ARG_REGION;
			argv[1].v.region = &t;
			argv[2].t = ARG_UINT;
			argv[2].v.i = $4;
			argv[3].t = ARG_UINT;
			argv[3].v.i = $5;
			argv[4].t = ARG_LAST;
			
			function(FUNC_CHPROT, 4, argv);
		}
	| SHARE var region var region share_type '\n'
		{
			struct argument argv[5];
			struct vm_region_desc t1;
			struct vm_region_desc t2;
			struct region* r;
			struct map* m1;
			struct map* m2;
			
			if ( $3.t == 1 ) {
				memset(&t1, 0, sizeof(t1));
				t1.start = $3.r.r.start;
				t1.end = $3.r.r.end;
				t1.cur = $3.r.r.cur;
				t1.max = $3.r.r.max;
			} else {
				if ( strcasecmp($3.r.s, "ALL") == 0) {
					yyerror("'all' may not be used as variable name");
					break;
				}
				r = regget($3.r.s);
				if ( r == NULL ) {
					yyerror("no such variable %s", $3.r.s);
					break;
				}
				memcpy(&t1, &r->map, sizeof(t1) );
			}

			if ( $5.t == 1 ) {
				memset(&t2, 0, sizeof(t2));
				t2.start = $5.r.r.start;
				t2.end = $5.r.r.end;
				t2.cur = $5.r.r.cur;
				t2.max = $5.r.r.max;
			} else {
				if ( strcasecmp($5.r.s, "ALL") == 0) {
					yyerror("'all' may not be used as variable name");
					break;
				}
				r = regget($5.r.s);
				if ( r == NULL ) {
					yyerror("no such variable %s", $5.r.s);
					break;
				}
				memcpy(&t2, &r->map, sizeof(t2) );
			}
			
			if ( strcasecmp($2, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			m1 = mapget($2);
			if ( m1 == NULL ) {
				yyerror("no such variable %s", $2);
				break;
			}
			
			if ( strcasecmp($4, "ALL") == 0) {
				yyerror("'all' may not be used as variable name");
				break;
			}
			m2 = mapget($4);
			if ( m2 == NULL ) {
				yyerror("no such variable %s", $4);
				break;
			}
			
			argv[0].t = ARG_VMMAP;
			argv[0].v.map = &m1->map;
			argv[1].t = ARG_REGION;
			argv[1].v.region = &t1;
			argv[2].t = ARG_VMMAP;
			argv[2].v.map = &m2->map;
			argv[3].t = ARG_REGION;
			argv[3].v.region = &t2;
			argv[4].t = ARG_UINT;
			argv[4].v.i = $6;
			argv[5].t = ARG_LAST;
			
			function(FUNC_SHARE, 5, argv);
		}
	| REGION var region '\n'
		{
			if ( $3.t == 1 ) {
				if ( regset($2, &$3.r.r) == -1 ) {
					yyerror("cannot store variable %s", $2);
					YYERROR;
				}
			} else if ( $3.t == 2 ) {
				if ( regcopy($2, $3.r.s) == -1 ) {
					yyerror("cannot store variable %s", $2);
					YYERROR;
				}
			} else {
				yyerror("region struct in unkown state");
				YYERROR;
			}
		}
	| MAP var map '\n'
		{
			if ( mapset($2, &$3) == -1 ) {
				yyerror("cannot store variable %s", $2);
				YYERROR;
			}
		}
	| SHOW type var '\n'
		{
			struct map* m;
			struct region* r;
			
			if($2 & TYPE_VMMAP) {
				if ( strcasecmp($3, "ALL") == 0) {
					for (m = maphead; m; m = m->next)
						show_vm_map(m->name, &m->map);
				} else {
					m = mapget($3);
					if ( m == NULL ) {
						yyerror("no such variable %s", $3);
					} else
						show_vm_map($3, &m->map);
				}
			} 
			if($2 & TYPE_REGION) {
				if ( strcasecmp($3, "ALL") == 0) {
					for (r = reghead; r; r = r->next)
						show_region(r->name, &r->map);
				} else {
					r = regget($3);
					if ( r == NULL ) 
						yyerror("no such variable %s", $3);
					 else
						show_region($3, &r->map);
				}
			}		
		}
	| QUIT '\n'
		{
			printf("have a nice day\n");
			exit(0);
		}
	| STRING dummy '\n'
		{
			yyerror("unkown commando: %s", $1);
		}
	| '\n'
	;
	
dummy
	: STRING
	| dummy STRING
	;

var
	: /* empty */ { $$ = "ALL"; }
	| STRING { $$ = $1; }
	;
	
map
	: OPENBRACELET address address mode_code mode_code CLOSEDBRACELET
		{
			$$.start = (address_t) $2;
			$$.end = (address_t) $3;
		}
	;

address
	:	NUMBER { $$ = $1; }
	;

mode_code
	: /* empty */ { $$ = 0; }
	| NUMBER
		{ 
			if ( $1 > 07 )
				yyerror("mode code should be between 0 and 7 (%d changed to %d)", 
						$1, $1 & 07);
			$$ = $1 & 07;
		}
	;

region
	: OPENBRACELET address address mode_code mode_code CLOSEDBRACELET
		{
			$$.t = 1;
			$$.r.r.start = (address_t) $2;
			$$.r.r.end = (address_t) $3;
			$$.r.r.cur = (unsigned char) $4;
			$$.r.r.max = (unsigned char) $5;
			$$.r.r.type = VM_MANAGER_ANON;
		}
	| STRING
		{
			$$.t = 2;
			$$.r.s = $1;
		}
	;

type
	: STRING
		{
			if ( strcasecmp($1, "ALL") == 0) {
				$$ = TYPE_ALL;
			} else if ( strcasecmp($1, "MAP") == 0) {
				$$ = TYPE_VMMAP;
			} else if ( strcasecmp($1, "REGION") == 0) {
				$$ = TYPE_REGION;
			} else {
				yyerror("unknown type '%s'", $1);
				$$ = 0;
			}
		}
	;

share_type
	: STRING
		{
			if ( strcasecmp($1, "RW") == 0 ) {
				$$ = VM_OBJ_SHARE_RW;
			} else if ( strcasecmp($1, "RO") == 0) {
				$$ = VM_OBJ_SHARE_RO;
			} else if ( strcasecmp($1, "COW") == 0) {
				$$ = VM_OBJ_SHARE_COW;
			} else if ( strcasecmp($1, "SNAP") == 0) {
				$$ = VM_OBJ_SHARE_SNAP;
			} else {
				yyerror("unknown type '%s'", $1);
				$$ = VM_OBJ_SHARE_RO;
			}
		}
	;
%%

struct keywords {
	char *name;
	int val;
	char *help;
} keywords[] = {
	{ "ADD", ADD, "add <vm_map> <region>" },
	{ "FREE", FREE, "free <vm_map> <region>" },
	{ "RESIZE", RESIZE, "resize <vm_map> <region> <region>" },
	{ "SHARE", SHARE, "share <vm_map> <region> <vm_map> <region>" },
	{ "CHMOD", CHMOD, "chmod <vm_map> <region> <mode> [<mode>]" },
	{ "GET", GET, "get <vm_map> <address> <region>" },
	{ "REGION", REGION, "region <name> { <address> <address> [<mode> [<mode>]]" },
	{ "MAP", MAP, "map <name> { <address> <address> }" },
	{ "SHOW", SHOW, "show [map | region | all] [<name> | all] " },
	{ "QUIT", QUIT, "quit" },
	{ "EXIT", QUIT, "exit" },
	{ NULL, }
};

char* infile;
int showstate = 0;

int
yyerror(char *fmt, ...)
{
	va_list ap;
	errors = 1;

	va_start(ap, fmt);
	fprintf(stderr, "%s:%d: ", infile, yyval.lineno);
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, "\n");
	va_end(ap);
	return (0);
}

int lookup(char *name)
{
	int i;
	
	if ( showstate == 1 ) {
		showstate = 0;
		if (debug > 1) fprintf(stderr, "lookup: %s => string (show)\n", name);
		return (STRING);
	}
	for (i = 0; keywords[i].name != NULL; i++)
		if (strcasecmp(name, keywords[i].name) == 0) {
			if (debug > 1) fprintf(stderr, "lookup: %s => %d\n", name, keywords[i].val);
			if ( (keywords[i].val) == (SHOW) ) {
				showstate = 1;
			}
			return (keywords[i].val);
		}
	if (debug > 1) fprintf(stderr, "lookup: %s => string\n", name);
	return (STRING);
}

int yylex(void)
{
	char buf[8096], *p, *val;
	int endc, c, next;
	int token;

	p = buf;
	while (( c = getc(fin)) == ' ' || c == '\t' ) ;
	
	if (c == '#' ) {
		while ((c = getc(fin)) != '\n' && c != EOF) ;
	}
	if ( c == '{' ) {
		return (OPENBRACELET);
	}
	if ( c == '}' ) {
		return (CLOSEDBRACELET);
	}
	if (isdigit(c)) {
		int index = 0, base = 10;
		uint32 n = 0;

		yylval.v.number = 0;
		while (1) {
			if (base == 10 || base == 8 ) {
				if (!isdigit(c))
					break;
				c -= '0';
				if ( base == 8 && c > 7 ) {
					yyerror("digit to big for octal");
					return (ERROR);
				}
			} else if (base == 16) {
				if (isdigit(c))
					c -= '0';
				else if (c >= 'a' && c <= 'f')
					c -= 'a' - 10;
				else if (c >= 'A' && c <= 'F')
					c -= 'A' - 10;
				else
					break;
			}
			n = n * base + c;

			if (n > UINT_MAX) {
				yyerror("number is too large");
				return (ERROR);
			}
			c = getc(fin);
			if (c == EOF)
				break;
			if (index++ == 0 && n == 0) {
				if ( c == 'x' || c == 'X' ) {
					base = 16;
					c = getc(fin);
					if (c == EOF)
						break;
				} else if ( isdigit(c) ) {
					base = 8;
				} 
			}
		}
		yylval.v.number = (uint32)n;

		if (c != EOF)
			ungetc(c, fin);
		if (debug > 1)
			fprintf(stderr, "number: %d\n", yylval.v.number);
		return (NUMBER);
	}

#define ISEXT(x)  ( x == '_' || x == '-' || x == '.' )

	if ( isalnum(c) ) {
		do {
			*p++ = c;
			if (p-buf >= sizeof buf) {
				yyerror("string too long");
				return (ERROR);
			}
		} while ((c = getc(fin)) != EOF && isalnum(c) || ISEXT(c) );
		ungetc(c, fin);
		*p = '\0';
		token = lookup(buf);
		yylval.v.string = strdup(buf);
		if (yylval.v.string == NULL)
			err(1, "yylex: strdup");
		return (token);
	}	
	if (c == '\n') {
		yylval.lineno = lineno;
		lineno++;
	}
	if (c == EOF)
		return (0);
	return (c);
}
#undef ISEXT(x)

static int regset(char *name, struct regmap* map)
{
	struct region *r, *t;

	if ( strcasecmp(name, "ALL") == 0) {
		yyerror("'all' may not be used as variable name");
		return (0);
	}

	if ( (r = regget(name)) == NULL ) {
		r = calloc(1, sizeof(*r));
		if (r == NULL)
			return (-1);
		r->name = strdup(name);
		if (r->name == NULL) {
			free(r);
			return (-1);
		}
		r->next = reghead;
		reghead = r;
	}
	/* XXX we should free the map first */
	memset(&r->map, 0, sizeof(r->map));
	r->map.start = map->start;
	r->map.end = map->end;
	r->map.cur = map->cur;
	r->map.max = map->max;
	r->map.type = map->type;
			
	return (0);
}

static int regcopy(char *name, char *source)
{
	struct region *r, *t;

	if ( strcasecmp(name, "ALL") == 0) {
		yyerror("'all' may not be used as variable name");
		return (0);
	}

	if ( (r = regget(name)) == NULL ) {
		r = calloc(1, sizeof(*r));
		if (r == NULL)
			return (-1);
		r->name = strdup(name);
		if (r->name == NULL) {
			free(r);
			return (-1);
		}
		r->next = reghead;
		reghead = r;
	}
	memset(&r->map, 0, sizeof(r->map));
	if ( (t = regget(source)) == NULL ) {
		yyerror("region: no such variable '%s', '%s' initialized", 
				source, name);
		return (0);
	}
	memcpy(&r->map, &t->map, sizeof(r->map));
	return (0);
}	

static struct region* regget(char *name)
{
	struct region *r;

	for (r = reghead; r; r = r->next)
		if (strcmp(name, r->name) == 0 )
			return (r);
	return (NULL);
}

static void show_region(char *name, struct vm_region_desc* reg)
{
	if ( reg == NULL ) {
		printf("%s: (null pointer)\n", name);
		return;
	}
/*	printf("%s: mapped from %p to %p\n", 
			name, vm_map->header.start, vm_map->header.end);
*/
		printf("region %s { %p %p 0%o 0%o }\n",
			name, reg->start, reg->end, reg->cur, reg->max);
}

static int	mapset(char *name, struct addrmap* map)
{
	struct map *m;

	if ( strcasecmp(name, "ALL") == 0) {
		yyerror("'all' may not be used as variable name");
	}

	if ( (m = mapget(name)) == NULL ) {
		m = calloc(1, sizeof(*m));
		if (m == NULL)
			return (-1);
		m->name = strdup(name);
		if (m->name == NULL) {
			free(m);
			return (-1);
		}
		m->next = maphead;
		maphead = m;
	}
	/* XXX we should free the map first */
	memset(&m->map, 0, sizeof(m->map));
	m->map.header.start = map->start;
	m->map.header.end = map->end;
	
	return (0);
}

static struct map* mapget(char *name)
{
	struct map *m;

	for (m = maphead; m; m = m->next)
		if (strcmp(name, m->name) == 0 )
			return (m);
	return (NULL);
}

static void show_vm_map(char *name, struct vm_map* vm_map)
{
	struct vm_region* t;
	int i;
	
	if ( vm_map == NULL ) {
		printf("%s: (null pointer)\n", name);
		return;
	}
/*	printf("%s: mapped from %p to %p\n", 
			name, vm_map->header.start, vm_map->header.end);
*/
	printf("map %s { %p %p }\n",
		name, vm_map->header.start, vm_map->header.end);
	
	t = &vm_map->header;
	i = 0;
	
	DOUBLEQ_FOREACH(t, t, regionq) {
		printf("\tregion %s%d { %p %p 0%o 0%o }\n", name, i,
				t->start, t->end, t->cur, t->max);
		i++;
	}
				
}

int main(int argc, char **argv)
{
	++argv, --argc;  /* skip over program name */
	
	if ( argc > 0 ) {
		fin = fopen( argv[0], "r" );
		infile = strdup(argv[0]);
		if (infile == NULL)
			err(1, "main: strdup");
	} else {
		fin = stdin;
		infile = "stdin";
	}
	vm_manager_init();
	vm_manager_add(VM_MANAGER_ANON, &vm_anon_manager);
	errors = 0;
	yyparse();
	return (errors ? -1 : 0);
}

char* vmerr2string(int err)
{
	switch (err) {
		case VM_OK:
			return "no error";
		case VM_FREE:
			return "this region is free";
		case VM_NIMP:
			return "not implemented";
		case VM_FAILED:
			return "call failed";
		case VM_INVAL:
			return "invalid entry";
		case VM_NOMEM:
			return "out of memory";
		case VM_ACCESS:
			return "bad access permissions";
		case VM_OVERLAP:
			return "region does overlap with another one";
		case VM_BADDESC:
			return "bad region descriptor";
		case VM_OUTOFMAP:
			return "hint is not in the vm_map";
		case VM_NOBUF:
			return "specified buffer to small";
		default:
			yyerror("unknown error %d\n", err);
			return "unknown error";
	}
}

int function(int f, int argc, struct argument* argv)
{
	int err;
	
	switch (f) {
		case FUNC_ADD:
			if ( argc != 2 ) {
				yyerror("not enough arguments for add");
				return 0;
			}
			if ( argv[0].t != ARG_VMMAP || argv[1].t != ARG_REGION ) {
				yyerror("bad arguments for add");
				return 0;
			}
			err = vm_region_add(argv[0].v.map, argv[1].v.region);
			if ( err != VM_OK ) 
				yyerror("add: %s", vmerr2string(err) );
			return 0;
		case FUNC_FREE:
			if ( argc != 2 ) {
				yyerror("not enough arguments for free");
				return 0;
			}
			if ( argv[0].t != ARG_VMMAP || argv[1].t != ARG_REGION ) {
				yyerror("bad arguments for free");
				return 0;
			}
			err = vm_region_free(argv[0].v.map, argv[1].v.region);
			if ( err != VM_OK ) 
				yyerror("free: %s", vmerr2string(err) );
			return 0;
		case FUNC_SHARE:
			if ( argc != 5 ) {
				yyerror("not enough arguments for share");
				return 0;
			}
			if ( argv[0].t != ARG_VMMAP || argv[1].t != ARG_REGION ||
					 argv[2].t != ARG_VMMAP || argv[3].t != ARG_REGION ||
					 argv[4].t != ARG_UINT ) {
				yyerror("bad arguments for share");
				return 0;
			}
			err = vm_region_share(argv[0].v.map, argv[1].v.region,
					argv[2].v.map, argv[3].v.region, argv[4].v.i);
			if ( err != VM_OK ) 
				yyerror("share: %s", vmerr2string(err) );
			return 0;
		case FUNC_RESIZE:
			yyerror("function not yet implemented");
			return 0;
		case FUNC_CHPROT:
			if ( argc != 4 ) {
				yyerror("not enough arguments for chmod");
				return 0;
			}
			if ( argv[0].t != ARG_VMMAP || argv[1].t != ARG_REGION || 
					argv[2].t != ARG_UINT || argv[3].t != ARG_UINT ) {
				yyerror("bad arguments for add");
				return 0;
			}
			err =	vm_region_chprot(argv[0].v.map, argv[1].v.region, 
					argv[2].v.i, argv[3].v.i);
			if ( err != VM_OK ) 
				yyerror("chmod: %s", vmerr2string(err) );
			return 0;
		case FUNC_GET:
			if ( argc != 3 ) {
				yyerror("not enough arguments for get");
				return 0;
			}
			if ( argv[0].t != ARG_VMMAP || argv[1].t != ARG_ADDRESS || 
					argv[2].t != ARG_REGION ) {
				yyerror("bad arguments for add");
				return 0;
			}
			err =	vm_region_get(argv[0].v.map, argv[1].v.addr, argv[2].v.region);
			if ( err != VM_OK ) 
				yyerror("get: %s", vmerr2string(err) );
			return 0;
		default:
			yyerror("unknown function");
			return 0;
	}
}

