[llvm-commits] [parallel] CVS: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/LICENSE.TXT Makefile alloca.c array.c awk.y builtin.c debug.c eval.c field.c gawk.h io.c main.c missing.c msg.c node.c patchlevel.h regex.c regex.h version.sh

Misha Brukman brukman at cs.uiuc.edu
Mon Mar 1 20:24:45 PST 2004


Changes in directory llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk:

LICENSE.TXT added (r1.1.2.1)
Makefile added (r1.1.2.1)
alloca.c added (r1.1.2.1)
array.c added (r1.1.2.1)
awk.y added (r1.1.2.1)
builtin.c added (r1.1.2.1)
debug.c added (r1.1.2.1)
eval.c added (r1.1.2.1)
field.c added (r1.1.2.1)
gawk.h added (r1.1.2.1)
io.c added (r1.1.2.1)
main.c added (r1.1.2.1)
missing.c added (r1.1.2.1)
msg.c added (r1.1.2.1)
node.c added (r1.1.2.1)
patchlevel.h added (r1.1.2.1)
regex.c added (r1.1.2.1)
regex.h added (r1.1.2.1)
version.sh added (r1.1.2.1)

---
Log message:

Merge from trunk

---
Diffs of the changes:  (+10097 -0)

Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/LICENSE.TXT
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/LICENSE.TXT:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/LICENSE.TXT	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,10 ----
+ gawk - Part of the Malloc Benchmark Suite
+ -------------------------------------------------------------------------------
+ All files are licensed under the LLVM license with the following additions:
+ 
+ These files are licensed to you under the GNU General Public License (version
+ 1 or later).  Redistribution must follow the additional restrictions required
+ by the GPL.
+ 
+ Please see individiual files for additional copyright information.
+ 


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/Makefile
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/Makefile:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/Makefile	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,20 ----
+ LEVEL = ../../../../../..
+ RUN_OPTIONS = -f $(SourceDir)/INPUT/adj.awk type=l linelen=70 indent=5 $(SourceDir)/INPUT/words-large.awk
+ PROG = gawk
+ LIBS += -lm
+ LDFLAGS += -lm
+ 
+ Source = alloca.c awk.tab.c debug.c field.c main.c msg.c regex.c array.c  \
+          builtin.c eval.c io.c node.c
+ 
+ all::
+ 
+ awk.tab.c: awk.y
+ 	$(YACC) -v awk.y
+ 	mv y.tab.c awk.tab.c
+ 
+ CPPFLAGS += -DBCOPY_MISSING -DSPRINTF_INT -DDOPRNT_MISSING  -DGCVT_MISSING -DSTRCASE_MISSING -DSTRTOD_MISSING  -DTMPNAM_MISSING
+ include ../../../Makefile.multisrc
+ 
+ clean::
+ 	rm -f awk.tab.c


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/alloca.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/alloca.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/alloca.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,205 ----
+ /*
+ 	alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+ 
+ 	last edit:	86/05/30	rms
+ 	   include config.h, since on VMS it renames some symbols.
+ 	   Use xmalloc instead of malloc.
+ 
+ 	This implementation of the PWB library alloca() function,
+ 	which is used to allocate space off the run-time stack so
+ 	that it is automatically reclaimed upon procedure exit, 
+ 	was inspired by discussions with J. Q. Johnson of Cornell.
+ 
+ 	It should work under any C implementation that uses an
+ 	actual procedure stack (as opposed to a linked list of
+ 	frames).  There are some preprocessor constants that can
+ 	be defined when compiling for your specific system, for
+ 	improved efficiency; however, the defaults should be okay.
+ 
+ 	The general concept of this implementation is to keep
+ 	track of all alloca()-allocated blocks, and reclaim any
+ 	that are found to be deeper in the stack than the current
+ 	invocation.  This heuristic does not reclaim storage as
+ 	soon as it becomes invalid, but it will do so eventually.
+ 
+ 	As a special case, alloca(0) reclaims storage without
+ 	allocating any.  It is a good idea to use alloca(0) in
+ 	your main control loop, etc. to force garbage collection.
+ */
+ #ifndef lint
+ static char	SCCSid[] = "@(#)alloca.c	1.1";	/* for the "what" utility */
+ #endif
+ 
+ #ifdef emacs
+ #include "config.h"
+ #ifdef static
+ /* actually, only want this if static is defined as ""
+    -- this is for usg, in which emacs must undefine static
+    in order to make unexec workable
+    */
+ #ifndef STACK_DIRECTION
+ you
+ lose
+ -- must know STACK_DIRECTION at compile-time
+ #endif /* STACK_DIRECTION undefined */
+ #endif /* static */
+ #endif /* emacs */
+ 
+ #ifdef X3J11
+ typedef void	*pointer;		/* generic pointer type */
+ #else
+ typedef char	*pointer;		/* generic pointer type */
+ #endif
+ 
+ #define	NULL	0			/* null pointer constant */
+ 
+ extern void	free();
+ extern pointer	xmalloc();
+ 
+ /*
+ 	Define STACK_DIRECTION if you know the direction of stack
+ 	growth for your system; otherwise it will be automatically
+ 	deduced at run-time.
+ 
+ 	STACK_DIRECTION > 0 => grows toward higher addresses
+ 	STACK_DIRECTION < 0 => grows toward lower addresses
+ 	STACK_DIRECTION = 0 => direction of growth unknown
+ */
+ 
+ #ifndef STACK_DIRECTION
+ #define	STACK_DIRECTION	0		/* direction unknown */
+ #endif
+ 
+ #if STACK_DIRECTION != 0
+ 
+ #define	STACK_DIR	STACK_DIRECTION	/* known at compile-time */
+ 
+ #else	/* STACK_DIRECTION == 0; need run-time code */
+ 
+ static int	stack_dir;		/* 1 or -1 once known */
+ #define	STACK_DIR	stack_dir
+ 
+ static void
+ find_stack_direction (/* void */)
+ {
+   static char	*addr = NULL;	/* address of first
+ 				   `dummy', once known */
+   auto char	dummy;		/* to get stack address */
+ 
+   if (addr == NULL)
+     {				/* initial entry */
+       addr = &dummy;
+ 
+       find_stack_direction ();	/* recurse once */
+     }
+   else				/* second entry */
+     if (&dummy > addr)
+       stack_dir = 1;		/* stack grew upward */
+     else
+       stack_dir = -1;		/* stack grew downward */
+ }
+ 
+ #endif	/* STACK_DIRECTION == 0 */
+ 
+ /*
+ 	An "alloca header" is used to:
+ 	(a) chain together all alloca()ed blocks;
+ 	(b) keep track of stack depth.
+ 
+ 	It is very important that sizeof(header) agree with malloc()
+ 	alignment chunk size.  The following default should work okay.
+ */
+ 
+ #ifndef	ALIGN_SIZE
+ #define	ALIGN_SIZE	sizeof(double)
+ #endif
+ 
+ typedef union hdr
+ {
+   char	align[ALIGN_SIZE];	/* to force sizeof(header) */
+   struct
+     {
+       union hdr *next;		/* for chaining headers */
+       char *deep;		/* for stack depth measure */
+     } h;
+ } header;
+ 
+ /*
+ 	alloca( size ) returns a pointer to at least `size' bytes of
+ 	storage which will be automatically reclaimed upon exit from
+ 	the procedure that called alloca().  Originally, this space
+ 	was supposed to be taken from the current stack frame of the
+ 	caller, but that method cannot be made to work for some
+ 	implementations of C, for example under Gould's UTX/32.
+ */
+ 
+ static header *last_alloca_header = NULL; /* -> last alloca header */
+ 
+ pointer
+ alloca (size)			/* returns pointer to storage */
+      unsigned	size;		/* # bytes to allocate */
+ {
+   auto char	probe;		/* probes stack depth: */
+   register char	*depth = &probe;
+ 
+ #if STACK_DIRECTION == 0
+   if (STACK_DIR == 0)		/* unknown growth direction */
+     find_stack_direction ();
+ #endif
+ 
+ 				/* Reclaim garbage, defined as all alloca()ed storage that
+ 				   was allocated from deeper in the stack than currently. */
+ 
+   {
+     register header	*hp;	/* traverses linked list */
+ 
+     for (hp = last_alloca_header; hp != NULL;)
+       if (STACK_DIR > 0 && hp->h.deep > depth
+ 	  || STACK_DIR < 0 && hp->h.deep < depth)
+ 	{
+ 	  register header	*np = hp->h.next;
+ 
+ 	  free ((pointer) hp);	/* collect garbage */
+ 
+ 	  hp = np;		/* -> next header */
+ 	}
+       else
+ 	break;			/* rest are not deeper */
+ 
+     last_alloca_header = hp;	/* -> last valid storage */
+   }
+ 
+   if (size == 0)
+     return NULL;		/* no allocation required */
+ 
+   /* Allocate combined header + user data storage. */
+ 
+   {
+     register pointer	new = xmalloc (sizeof (header) + size);
+     /* address of header */
+ 
+     ((header *)new)->h.next = last_alloca_header;
+     ((header *)new)->h.deep = depth;
+ 
+     last_alloca_header = (header *)new;
+ 
+     /* User storage begins just after header. */
+ 
+     return (pointer)((char *)new + sizeof(header));
+   }
+ }
+ 
+ pointer xmalloc(n)
+ unsigned int n;
+ {
+   extern pointer malloc();
+   pointer cp;
+   static char mesg[] = "xmalloc: no memory!\n";
+ 
+   cp = malloc(n);
+   if (! cp) {
+     write (2, mesg, sizeof(mesg) - 1);
+     exit(1);
+   }
+   return cp;
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/array.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/array.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/array.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,265 ----
+ /*
+  * array.c - routines for associative arrays.
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ #ifdef DONTDEF
+ int primes[] = {31, 61, 127, 257, 509, 1021, 2053, 4099, 8191, 16381};
+ #endif
+ 
+ #define ASSOC_HASHSIZE 127
+ #define STIR_BITS(n) ((n) << 5 | (((n) >> 27) & 0x1f))
+ #define HASHSTEP(old, c) ((old << 1) + c)
+ #define MAKE_POS(v) (v & ~0x80000000)	/* make number positive */
+ 
+ NODE *
+ concat_exp(tree)
+ NODE *tree;
+ {
+ 	NODE *r;
+ 	char *str;
+ 	char *s;
+ 	unsigned len;
+ 	int offset;
+ 	int subseplen;
+ 	char *subsep;
+ 
+ 	if (tree->type != Node_expression_list)
+ 		return force_string(tree_eval(tree));
+ 	r = force_string(tree_eval(tree->lnode));
+ 	if (tree->rnode == NULL)
+ 		return r;
+ 	subseplen = SUBSEP_node->lnode->stlen;
+ 	subsep = SUBSEP_node->lnode->stptr;
+ 	len = r->stlen + subseplen + 1;
+ 	emalloc(str, char *, len, "concat_exp");
+ 	memcpy(str, r->stptr, r->stlen+1);
+ 	s = str + r->stlen;
+ 	free_temp(r);
+ 	tree = tree->rnode;
+ 	while (tree) {
+ 		if (subseplen == 1)
+ 			*s++ = *subsep;
+ 		else {
+ 			memcpy(s, subsep, subseplen+1);
+ 			s += subseplen;
+ 		}
+ 		r = force_string(tree_eval(tree->lnode));
+ 		len += r->stlen + subseplen;
+ 		offset = s - str;
+ 		erealloc(str, char *, len, "concat_exp");
+ 		s = str + offset;
+ 		memcpy(s, r->stptr, r->stlen+1);
+ 		s += r->stlen;
+ 		free_temp(r);
+ 		tree = tree->rnode;
+ 	}
+ 	r = tmp_string(str, s - str);
+ 	free(str);
+ 	return r;
+ }
+ 
+ /* Flush all the values in symbol[] before doing a split() */
+ void
+ assoc_clear(symbol)
+ NODE *symbol;
+ {
+ 	int i;
+ 	NODE *bucket, *next;
+ 
+ 	if (symbol->var_array == 0)
+ 		return;
+ 	for (i = 0; i < ASSOC_HASHSIZE; i++) {
+ 		for (bucket = symbol->var_array[i]; bucket; bucket = next) {
+ 			next = bucket->ahnext;
+ 			deref = bucket->ahname;
+ 			do_deref();
+ 			deref = bucket->ahvalue;
+ 			do_deref();
+ 			freenode(bucket);
+ 		}
+ 		symbol->var_array[i] = 0;
+ 	}
+ }
+ 
+ /*
+  * calculate the hash function of the string subs, also returning in *typtr
+  * the type (string or number) 
+  */
+ static int
+ hash_calc(subs)
+ NODE *subs;
+ {
+ 	register int hash1 = 0, i;
+ 
+ 	subs = force_string(subs);
+ 	for (i = 0; i < subs->stlen; i++)
+ 		hash1 = HASHSTEP(hash1, subs->stptr[i]);
+ 
+ 	hash1 = MAKE_POS(STIR_BITS((int) hash1)) % ASSOC_HASHSIZE;
+ 	return (hash1);
+ }
+ 
+ /*
+  * locate symbol[subs], given hash of subs and type 
+  */
+ static NODE *				/* NULL if not found */
+ assoc_find(symbol, subs, hash1)
+ NODE *symbol, *subs;
+ int hash1;
+ {
+ 	register NODE *bucket;
+ 
+ 	for (bucket = symbol->var_array[hash1]; bucket; bucket = bucket->ahnext) {
+ 		if (cmp_nodes(bucket->ahname, subs))
+ 			continue;
+ 		return bucket;
+ 	}
+ 	return NULL;
+ }
+ 
+ /*
+  * test whether the array element symbol[subs] exists or not 
+  */
+ int
+ in_array(symbol, subs)
+ NODE *symbol, *subs;
+ {
+ 	register int hash1;
+ 
+ 	if (symbol->type == Node_param_list)
+ 		symbol = stack_ptr[symbol->param_cnt];
+ 	if (symbol->var_array == 0)
+ 		return 0;
+ 	subs = concat_exp(subs);
+ 	hash1 = hash_calc(subs);
+ 	if (assoc_find(symbol, subs, hash1) == NULL) {
+ 		free_temp(subs);
+ 		return 0;
+ 	} else {
+ 		free_temp(subs);
+ 		return 1;
+ 	}
+ }
+ 
+ /*
+  * SYMBOL is the address of the node (or other pointer) being dereferenced.
+  * SUBS is a number or string used as the subscript. 
+  *
+  * Find SYMBOL[SUBS] in the assoc array.  Install it with value "" if it
+  * isn't there. Returns a pointer ala get_lhs to where its value is stored 
+  */
+ NODE **
+ assoc_lookup(symbol, subs)
+ NODE *symbol, *subs;
+ {
+ 	register int hash1, i;
+ 	register NODE *bucket;
+ 
+ 	hash1 = hash_calc(subs);
+ 
+ 	if (symbol->var_array == 0) {	/* this table really should grow
+ 					 * dynamically */
+ 		emalloc(symbol->var_array, NODE **, (sizeof(NODE *) *
+ 			ASSOC_HASHSIZE), "assoc_lookup");
+ 		for (i = 0; i < ASSOC_HASHSIZE; i++)
+ 			symbol->var_array[i] = 0;
+ 		symbol->type = Node_var_array;
+ 	} else {
+ 		bucket = assoc_find(symbol, subs, hash1);
+ 		if (bucket != NULL) {
+ 			free_temp(subs);
+ 			return &(bucket->ahvalue);
+ 		}
+ 	}
+ 	bucket = newnode(Node_ahash);
+ 	bucket->ahname = dupnode(subs);
+ 	bucket->ahvalue = Nnull_string;
+ 	bucket->ahnext = symbol->var_array[hash1];
+ 	symbol->var_array[hash1] = bucket;
+ 	return &(bucket->ahvalue);
+ }
+ 
+ void
+ do_delete(symbol, tree)
+ NODE *symbol, *tree;
+ {
+ 	register int hash1;
+ 	register NODE *bucket, *last;
+ 	NODE *subs;
+ 
+ 	if (symbol->var_array == 0)
+ 		return;
+ 	subs = concat_exp(tree);
+ 	hash1 = hash_calc(subs);
+ 
+ 	last = NULL;
+ 	for (bucket = symbol->var_array[hash1]; bucket; last = bucket, bucket = bucket->ahnext)
+ 		if (cmp_nodes(bucket->ahname, subs) == 0)
+ 			break;
+ 	free_temp(subs);
+ 	if (bucket == NULL)
+ 		return;
+ 	if (last)
+ 		last->ahnext = bucket->ahnext;
+ 	else
+ 		symbol->var_array[hash1] = bucket->ahnext;
+ 	deref = bucket->ahname;
+ 	do_deref();
+ 	deref = bucket->ahvalue;
+ 	do_deref();
+ 	freenode(bucket);
+ }
+ 
+ struct search *
+ assoc_scan(symbol)
+ NODE *symbol;
+ {
+ 	struct search *lookat;
+ 
+ 	if (!symbol->var_array)
+ 		return 0;
+ 	emalloc(lookat, struct search *, sizeof(struct search), "assoc_scan");
+ 	lookat->numleft = ASSOC_HASHSIZE;
+ 	lookat->arr_ptr = symbol->var_array;
+ 	lookat->bucket = symbol->var_array[0];
+ 	return assoc_next(lookat);
+ }
+ 
+ struct search *
+ assoc_next(lookat)
+ struct search *lookat;
+ {
+ 	for (; lookat->numleft; lookat->numleft--) {
+ 		while (lookat->bucket != 0) {
+ 			lookat->retval = lookat->bucket->ahname;
+ 			lookat->bucket = lookat->bucket->ahnext;
+ 			return lookat;
+ 		}
+ 		lookat->bucket = *++(lookat->arr_ptr);
+ 	}
+ 	free((char *) lookat);
+ 	return 0;
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/awk.y
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/awk.y:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/awk.y	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,1694 ----
+ /*
+  * awk.y --- yacc/bison parser
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ %{
+ #ifdef DEBUG
+ #define YYDEBUG 12
+ #endif
+ 
+ #include "gawk.h"
+ 
+ /*
+  * This line is necessary since the Bison parser skeleton uses bcopy.
+  * Systems without memcpy should use -DMEMCPY_MISSING, per the Makefile.
+  * It should not hurt anything if Yacc is being used instead of Bison.
+  */
+ #define bcopy(s,d,n)	memcpy((d),(s),(n))
+ 
+ extern void msg(char * message, ...);
+ extern struct re_pattern_buffer *mk_re_parse();
+ 
+ NODE *node();
+ NODE *lookup();
+ NODE *install();
+ 
+ static NODE *snode();
+ static NODE *mkrangenode();
+ static FILE *pathopen();
+ static NODE *make_for_loop();
+ static NODE *append_right();
+ static void func_install();
+ static NODE *make_param();
+ static int hashf();
+ static void pop_params();
+ static void pop_var();
+ static int yylex ();
+ static void yyerror(char * msg, ...);
+ 
+ static int want_regexp;		/* lexical scanning kludge */
+ static int want_assign;		/* lexical scanning kludge */
+ static int can_return;		/* lexical scanning kludge */
+ static int io_allowed = 1;	/* lexical scanning kludge */
+ static int lineno = 1;		/* for error msgs */
+ static char *lexptr;		/* pointer to next char during parsing */
+ static char *lexptr_begin;	/* keep track of where we were for error msgs */
+ static int curinfile = -1;	/* index into sourcefiles[] */
+ static int param_counter;
+ 
+ NODE *variables[HASHSIZE];
+ 
+ extern int errcount;
+ extern NODE *begin_block;
+ extern NODE *end_block;
+ %}
+ 
+ %union {
+ 	long lval;
+ 	AWKNUM fval;
+ 	NODE *nodeval;
+ 	NODETYPE nodetypeval;
+ 	char *sval;
+ 	NODE *(*ptrval)();
+ }
+ 
+ %type <nodeval> function_prologue function_body
+ %type <nodeval> rexp exp start program rule simp_exp
+ %type <nodeval> pattern 
+ %type <nodeval>	action variable param_list
+ %type <nodeval>	rexpression_list opt_rexpression_list
+ %type <nodeval>	expression_list opt_expression_list
+ %type <nodeval>	statements statement if_statement opt_param_list 
+ %type <nodeval> opt_exp opt_variable regexp 
+ %type <nodeval> input_redir output_redir
+ %type <nodetypeval> r_paren comma nls opt_nls print
+ 
+ %type <sval> func_name
+ %token <sval> FUNC_CALL NAME REGEXP
+ %token <lval> ERROR
+ %token <nodeval> NUMBER YSTRING
+ %token <nodetypeval> RELOP APPEND_OP
+ %token <nodetypeval> ASSIGNOP MATCHOP NEWLINE CONCAT_OP
+ %token <nodetypeval> LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
+ %token <nodetypeval> LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
+ %token <nodetypeval> LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
+ %token <nodetypeval> LEX_GETLINE
+ %token <nodetypeval> LEX_IN
+ %token <lval> LEX_AND LEX_OR INCREMENT DECREMENT
+ %token <ptrval> LEX_BUILTIN LEX_LENGTH
+ 
+ /* these are just yylval numbers */
+ 
+ /* Lowest to highest */
+ %right ASSIGNOP
+ %right '?' ':'
+ %left LEX_OR
+ %left LEX_AND
+ %left LEX_GETLINE
+ %nonassoc LEX_IN
+ %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
+ %nonassoc MATCHOP
+ %nonassoc RELOP '<' '>' '|' APPEND_OP
+ %left CONCAT_OP
+ %left YSTRING NUMBER
+ %left '+' '-'
+ %left '*' '/' '%'
+ %right '!' UNARY
+ %right '^'
+ %left INCREMENT DECREMENT
+ %left '$'
+ %left '(' ')'
+ 
+ %%
+ 
+ start
+ 	: opt_nls program opt_nls
+ 		{ expression_value = $2; }
+ 	;
+ 
+ program
+ 	: rule
+ 		{ 
+ 			if ($1 != NULL)
+ 				$$ = $1;
+ 			else
+ 				$$ = NULL;
+ 			yyerrok;
+ 		}
+ 	| program rule
+ 		/* add the rule to the tail of list */
+ 		{
+ 			if ($2 == NULL)
+ 				$$ = $1;
+ 			else if ($1 == NULL)
+ 				$$ = $2;
+ 			else {
+ 				if ($1->type != Node_rule_list)
+ 					$1 = node($1, Node_rule_list,
+ 						(NODE*)NULL);
+ 				$$ = append_right ($1,
+ 				   node($2, Node_rule_list,(NODE *) NULL));
+ 			}
+ 			yyerrok;
+ 		}
+ 	| error	{ $$ = NULL; }
+ 	| program error { $$ = NULL; }
+ 	;
+ 
+ rule
+ 	: LEX_BEGIN { io_allowed = 0; }
+ 	  action
+ 	  {
+ 		if (begin_block) {
+ 			if (begin_block->type != Node_rule_list)
+ 				begin_block = node(begin_block, Node_rule_list,
+ 					(NODE *)NULL);
+ 			append_right (begin_block, node(
+ 			    node((NODE *)NULL, Node_rule_node, $3),
+ 			    Node_rule_list, (NODE *)NULL) );
+ 		} else
+ 			begin_block = node((NODE *)NULL, Node_rule_node, $3);
+ 		$$ = NULL;
+ 		io_allowed = 1;
+ 		yyerrok;
+ 	  }
+ 	| LEX_END { io_allowed = 0; }
+ 	  action
+ 	  {
+ 		if (end_block) {
+ 			if (end_block->type != Node_rule_list)
+ 				end_block = node(end_block, Node_rule_list,
+ 					(NODE *)NULL);
+ 			append_right (end_block, node(
+ 			    node((NODE *)NULL, Node_rule_node, $3),
+ 			    Node_rule_list, (NODE *)NULL));
+ 		} else
+ 			end_block = node((NODE *)NULL, Node_rule_node, $3);
+ 		$$ = NULL;
+ 		io_allowed = 1;
+ 		yyerrok;
+ 	  }
+ 	| LEX_BEGIN statement_term
+ 	  {
+ 		msg ("error near line %d: BEGIN blocks must have an action part", lineno);
+ 		errcount++;
+ 		yyerrok;
+ 	  }
+ 	| LEX_END statement_term
+ 	  {
+ 		msg ("error near line %d: END blocks must have an action part", lineno);
+ 		errcount++;
+ 		yyerrok;
+ 	  }
+ 	| pattern action
+ 		{ $$ = node ($1, Node_rule_node, $2); yyerrok; }
+ 	| action
+ 		{ $$ = node ((NODE *)NULL, Node_rule_node, $1); yyerrok; }
+ 	| pattern statement_term
+ 		{ if($1) $$ = node ($1, Node_rule_node, (NODE *)NULL); yyerrok; }
+ 	| function_prologue function_body
+ 		{
+ 			func_install($1, $2);
+ 			$$ = NULL;
+ 			yyerrok;
+ 		}
+ 	;
+ 
+ func_name
+ 	: NAME
+ 		{ $$ = $1; }
+ 	| FUNC_CALL
+ 		{ $$ = $1; }
+ 	;
+ 		
+ function_prologue
+ 	: LEX_FUNCTION 
+ 		{
+ 			param_counter = 0;
+ 		}
+ 	  func_name '(' opt_param_list r_paren opt_nls
+ 		{
+ 			$$ = append_right(make_param($3), $5);
+ 			can_return = 1;
+ 		}
+ 	;
+ 
+ function_body
+ 	: l_brace statements r_brace
+ 	  {
+ 		$$ = $2;
+ 		can_return = 0;
+ 	  }
+ 	;
+ 
+ 
+ pattern
+ 	: exp
+ 		{ $$ = $1; }
+ 	| exp comma exp
+ 		{ $$ = mkrangenode ( node($1, Node_cond_pair, $3) ); }
+ 	;
+ 
+ regexp
+ 	/*
+ 	 * In this rule, want_regexp tells yylex that the next thing
+ 	 * is a regexp so it should read up to the closing slash.
+ 	 */
+ 	: '/'
+ 		{ ++want_regexp; }
+ 	   REGEXP '/'
+ 		{
+ 		  want_regexp = 0;
+ 		  $$ = node((NODE *)NULL,Node_regex,(NODE *)mk_re_parse($3, 0));
+ 		  $$ -> re_case = 0;
+ 		  emalloc ($$ -> re_text, char *, strlen($3)+1, "regexp");
+ 		  strcpy ($$ -> re_text, $3);
+ 		}
+ 	;
+ 
+ action
+ 	: l_brace r_brace opt_semi
+ 		{
+ 			/* empty actions are different from missing actions */
+ 			$$ = node ((NODE *) NULL, Node_illegal, (NODE *) NULL);
+ 		}
+ 	| l_brace statements r_brace opt_semi
+ 		{ $$ = $2 ; }
+ 	;
+ 
+ statements
+ 	: statement
+ 		{ $$ = $1; }
+ 	| statements statement
+ 		{
+ 			if ($1 == NULL || $1->type != Node_statement_list)
+ 				$1 = node($1, Node_statement_list,(NODE *)NULL);
+ 	    		$$ = append_right($1,
+ 				node( $2, Node_statement_list, (NODE *)NULL));
+ 	    		yyerrok;
+ 		}
+ 	| error
+ 		{ $$ = NULL; }
+ 	| statements error
+ 		{ $$ = NULL; }
+ 	;
+ 
+ statement_term
+ 	: nls
+ 		{ $<nodetypeval>$ = Node_illegal; }
+ 	| semi opt_nls
+ 		{ $<nodetypeval>$ = Node_illegal; }
+ 	;
+ 
+ 	
+ statement
+ 	: semi opt_nls
+ 		{ $$ = NULL; }
+ 	| l_brace r_brace
+ 		{ $$ = NULL; }
+ 	| l_brace statements r_brace
+ 		{ $$ = $2; }
+ 	| if_statement
+ 		{ $$ = $1; }
+ 	| LEX_WHILE '(' exp r_paren opt_nls statement
+ 		{ $$ = node ($3, Node_K_while, $6); }
+ 	| LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
+ 		{ $$ = node ($6, Node_K_do, $3); }
+ 	| LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
+ 	  {
+ 		$$ = node ($8, Node_K_arrayfor, make_for_loop(variable($3),
+ 			(NODE *)NULL, variable($5)));
+ 	  }
+ 	| LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
+ 	  {
+ 		$$ = node($10, Node_K_for, (NODE *)make_for_loop($3, $5, $7));
+ 	  }
+ 	| LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
+ 	  {
+ 		$$ = node ($9, Node_K_for,
+ 			(NODE *)make_for_loop($3, (NODE *)NULL, $6));
+ 	  }
+ 	| LEX_BREAK statement_term
+ 	   /* for break, maybe we'll have to remember where to break to */
+ 		{ $$ = node ((NODE *)NULL, Node_K_break, (NODE *)NULL); }
+ 	| LEX_CONTINUE statement_term
+ 	   /* similarly */
+ 		{ $$ = node ((NODE *)NULL, Node_K_continue, (NODE *)NULL); }
+ 	| print '(' expression_list r_paren output_redir statement_term
+ 		{ $$ = node ($3, $1, $5); }
+ 	| print opt_rexpression_list output_redir statement_term
+ 		{ $$ = node ($2, $1, $3); }
+ 	| LEX_NEXT
+ 		{ if (! io_allowed) yyerror("next used in BEGIN or END action"); }
+ 	  statement_term
+ 		{ $$ = node ((NODE *)NULL, Node_K_next, (NODE *)NULL); }
+ 	| LEX_EXIT opt_exp statement_term
+ 		{ $$ = node ($2, Node_K_exit, (NODE *)NULL); }
+ 	| LEX_RETURN
+ 		{ if (! can_return) yyerror("return used outside function context"); }
+ 	  opt_exp statement_term
+ 		{ $$ = node ($3, Node_K_return, (NODE *)NULL); }
+ 	| LEX_DELETE NAME '[' expression_list ']' statement_term
+ 		{ $$ = node (variable($2), Node_K_delete, $4); }
+ 	| exp statement_term
+ 		{ $$ = $1; }
+ 	;
+ 
+ print
+ 	: LEX_PRINT
+ 		{ $$ = $1; }
+ 	| LEX_PRINTF
+ 		{ $$ = $1; }
+ 	;
+ 
+ if_statement
+ 	: LEX_IF '(' exp r_paren opt_nls statement
+ 	  {
+ 		$$ = node($3, Node_K_if, 
+ 			node($6, Node_if_branches, (NODE *)NULL));
+ 	  }
+ 	| LEX_IF '(' exp r_paren opt_nls statement
+ 	     LEX_ELSE opt_nls statement
+ 		{ $$ = node ($3, Node_K_if,
+ 				node ($6, Node_if_branches, $9)); }
+ 	;
+ 
+ nls
+ 	: NEWLINE
+ 		{ $<nodetypeval>$ = 0; }
+ 	| nls NEWLINE
+ 		{ $<nodetypeval>$ = 0; }
+ 	;
+ 
+ opt_nls
+ 	: /* empty */
+ 		{ $<nodetypeval>$ = 0; }
+ 	| nls
+ 		{ $<nodetypeval>$ = 0; }
+ 	;
+ 
+ input_redir
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| '<' simp_exp
+ 		{ $$ = node ($2, Node_redirect_input, (NODE *)NULL); }
+ 	;
+ 
+ output_redir
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| '>' exp
+ 		{ $$ = node ($2, Node_redirect_output, (NODE *)NULL); }
+ 	| APPEND_OP exp
+ 		{ $$ = node ($2, Node_redirect_append, (NODE *)NULL); }
+ 	| '|' exp
+ 		{ $$ = node ($2, Node_redirect_pipe, (NODE *)NULL); }
+ 	;
+ 
+ opt_param_list
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| param_list
+ 		{ $$ = $1; }
+ 	;
+ 
+ param_list
+ 	: NAME
+ 		{ $$ = make_param($1); }
+ 	| param_list comma NAME
+ 		{ $$ = append_right($1, make_param($3)); yyerrok; }
+ 	| error
+ 		{ $$ = NULL; }
+ 	| param_list error
+ 		{ $$ = NULL; }
+ 	| param_list comma error
+ 		{ $$ = NULL; }
+ 	;
+ 
+ /* optional expression, as in for loop */
+ opt_exp
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| exp
+ 		{ $$ = $1; }
+ 	;
+ 
+ opt_rexpression_list
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| rexpression_list
+ 		{ $$ = $1; }
+ 	;
+ 
+ rexpression_list
+ 	: rexp
+ 		{ $$ = node ($1, Node_expression_list, (NODE *)NULL); }
+ 	| rexpression_list comma rexp
+ 	  {
+ 		$$ = append_right($1,
+ 			node( $3, Node_expression_list, (NODE *)NULL));
+ 		yyerrok;
+ 	  }
+ 	| error
+ 		{ $$ = NULL; }
+ 	| rexpression_list error
+ 		{ $$ = NULL; }
+ 	| rexpression_list error rexp
+ 		{ $$ = NULL; }
+ 	| rexpression_list comma error
+ 		{ $$ = NULL; }
+ 	;
+ 
+ opt_expression_list
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| expression_list
+ 		{ $$ = $1; }
+ 	;
+ 
+ expression_list
+ 	: exp
+ 		{ $$ = node ($1, Node_expression_list, (NODE *)NULL); }
+ 	| expression_list comma exp
+ 		{
+ 			$$ = append_right($1,
+ 				node( $3, Node_expression_list, (NODE *)NULL));
+ 			yyerrok;
+ 		}
+ 	| error
+ 		{ $$ = NULL; }
+ 	| expression_list error
+ 		{ $$ = NULL; }
+ 	| expression_list error exp
+ 		{ $$ = NULL; }
+ 	| expression_list comma error
+ 		{ $$ = NULL; }
+ 	;
+ 
+ /* Expressions, not including the comma operator.  */
+ exp	: variable ASSIGNOP
+ 		{ want_assign = 0; }
+ 		exp
+ 		{ $$ = node ($1, $2, $4); }
+ 	| '(' expression_list r_paren LEX_IN NAME
+ 		{ $$ = node (variable($5), Node_in_array, $2); }
+ 	| exp '|' LEX_GETLINE opt_variable
+ 		{
+ 		  $$ = node ($4, Node_K_getline,
+ 			 node ($1, Node_redirect_pipein, (NODE *)NULL));
+ 		}
+ 	| LEX_GETLINE opt_variable input_redir
+ 		{
+ 		  /* "too painful to do right" */
+ 		  /*
+ 		  if (! io_allowed && $3 == NULL)
+ 			yyerror("non-redirected getline illegal inside BEGIN or END action");
+ 		  */
+ 		  $$ = node ($2, Node_K_getline, $3);
+ 		}
+ 	| exp LEX_AND exp
+ 		{ $$ = node ($1, Node_and, $3); }
+ 	| exp LEX_OR exp
+ 		{ $$ = node ($1, Node_or, $3); }
+ 	| exp MATCHOP exp
+ 		 { $$ = node ($1, $2, $3); }
+ 	| regexp
+ 		{ $$ = $1; }
+ 	| '!' regexp %prec UNARY
+ 		{ $$ = node((NODE *) NULL, Node_nomatch, $2); }
+ 	| exp LEX_IN NAME
+ 		{ $$ = node (variable($3), Node_in_array, $1); }
+ 	| exp RELOP exp
+ 		{ $$ = node ($1, $2, $3); }
+ 	| exp '<' exp
+ 		{ $$ = node ($1, Node_less, $3); }
+ 	| exp '>' exp
+ 		{ $$ = node ($1, Node_greater, $3); }
+ 	| exp '?' exp ':' exp
+ 		{ $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
+ 	| simp_exp
+ 		{ $$ = $1; }
+ 	| exp exp %prec CONCAT_OP
+ 		{ $$ = node ($1, Node_concat, $2); }
+ 	;
+ 
+ rexp	
+ 	: variable ASSIGNOP
+ 		{ want_assign = 0; }
+ 		rexp
+ 		{ $$ = node ($1, $2, $4); }
+ 	| rexp LEX_AND rexp
+ 		{ $$ = node ($1, Node_and, $3); }
+ 	| rexp LEX_OR rexp
+ 		{ $$ = node ($1, Node_or, $3); }
+ 	| LEX_GETLINE opt_variable input_redir
+ 		{
+ 		  /* "too painful to do right" */
+ 		  /*
+ 		  if (! io_allowed && $3 == NULL)
+ 			yyerror("non-redirected getline illegal inside BEGIN or END action");
+ 		  */
+ 		  $$ = node ($2, Node_K_getline, $3);
+ 		}
+ 	| regexp
+ 		{ $$ = $1; } 
+ 	| '!' regexp %prec UNARY
+ 		{ $$ = node((NODE *) NULL, Node_nomatch, $2); }
+ 	| rexp MATCHOP rexp
+ 		 { $$ = node ($1, $2, $3); }
+ 	| rexp LEX_IN NAME
+ 		{ $$ = node (variable($3), Node_in_array, $1); }
+ 	| rexp RELOP rexp
+ 		{ $$ = node ($1, $2, $3); }
+ 	| rexp '?' rexp ':' rexp
+ 		{ $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
+ 	| simp_exp
+ 		{ $$ = $1; }
+ 	| rexp rexp %prec CONCAT_OP
+ 		{ $$ = node ($1, Node_concat, $2); }
+ 	;
+ 
+ simp_exp
+ 	: '!' simp_exp %prec UNARY
+ 		{ $$ = node ($2, Node_not,(NODE *) NULL); }
+ 	| '(' exp r_paren
+ 		{ $$ = $2; }
+ 	| LEX_BUILTIN '(' opt_expression_list r_paren
+ 		{ $$ = snode ($3, Node_builtin, $1); }
+ 	| LEX_LENGTH '(' opt_expression_list r_paren
+ 		{ $$ = snode ($3, Node_builtin, $1); }
+ 	| LEX_LENGTH
+ 		{ $$ = snode ((NODE *)NULL, Node_builtin, $1); }
+ 	| FUNC_CALL '(' opt_expression_list r_paren
+ 	  {
+ 		$$ = node ($3, Node_func_call, make_string($1, strlen($1)));
+ 	  }
+ 	| INCREMENT variable
+ 		{ $$ = node ($2, Node_preincrement, (NODE *)NULL); }
+ 	| DECREMENT variable
+ 		{ $$ = node ($2, Node_predecrement, (NODE *)NULL); }
+ 	| variable INCREMENT
+ 		{ $$ = node ($1, Node_postincrement, (NODE *)NULL); }
+ 	| variable DECREMENT
+ 		{ $$ = node ($1, Node_postdecrement, (NODE *)NULL); }
+ 	| variable
+ 		{ $$ = $1; }
+ 	| NUMBER
+ 		{ $$ = $1; }
+ 	| YSTRING
+ 		{ $$ = $1; }
+ 
+ 	/* Binary operators in order of decreasing precedence.  */
+ 	| simp_exp '^' simp_exp
+ 		{ $$ = node ($1, Node_exp, $3); }
+ 	| simp_exp '*' simp_exp
+ 		{ $$ = node ($1, Node_times, $3); }
+ 	| simp_exp '/' simp_exp
+ 		{ $$ = node ($1, Node_quotient, $3); }
+ 	| simp_exp '%' simp_exp
+ 		{ $$ = node ($1, Node_mod, $3); }
+ 	| simp_exp '+' simp_exp
+ 		{ $$ = node ($1, Node_plus, $3); }
+ 	| simp_exp '-' simp_exp
+ 		{ $$ = node ($1, Node_minus, $3); }
+ 	| '-' simp_exp    %prec UNARY
+ 		{ $$ = node ($2, Node_unary_minus, (NODE *)NULL); }
+ 	| '+' simp_exp    %prec UNARY
+ 		{ $$ = $2; }
+ 	;
+ 
+ opt_variable
+ 	: /* empty */
+ 		{ $$ = NULL; }
+ 	| variable
+ 		{ $$ = $1; }
+ 	;
+ 
+ variable
+ 	: NAME
+ 		{ want_assign = 1; $$ = variable ($1); }
+ 	| NAME '[' expression_list ']'
+ 		{ want_assign = 1; $$ = node (variable($1), Node_subscript, $3); }
+ 	| '$' simp_exp
+ 		{ want_assign = 1; $$ = node ($2, Node_field_spec, (NODE *)NULL); }
+ 	;
+ 
+ l_brace
+ 	: '{' opt_nls
+ 	;
+ 
+ r_brace
+ 	: '}' opt_nls	{ yyerrok; }
+ 	;
+ 
+ r_paren
+ 	: ')' { $<nodetypeval>$ = Node_illegal; yyerrok; }
+ 	;
+ 
+ opt_semi
+ 	: /* empty */
+ 	| semi
+ 	;
+ 
+ semi
+ 	: ';'	{ yyerrok; }
+ 	;
+ 
+ comma	: ',' opt_nls	{ $<nodetypeval>$ = Node_illegal; yyerrok; }
+ 	;
+ 
+ %%
+ 
+ struct token {
+ 	char *operator;		/* text to match */
+ 	NODETYPE value;		/* node type */
+ 	int class;		/* lexical class */
+ 	short nostrict;		/* ignore if in strict compatibility mode */
+ 	NODE *(*ptr) ();	/* function that implements this keyword */
+ };
+ 
+ extern NODE
+ 	*do_exp(),	*do_getline(),	*do_index(),	*do_length(),
+ 	*do_sqrt(),	*do_log(),	*do_sprintf(),	*do_substr(),
+ 	*do_split(),	*do_system(),	*do_int(),	*do_close(),
+ 	*do_atan2(),	*do_sin(),	*do_cos(),	*do_rand(),
+ 	*do_srand(),	*do_match(),	*do_tolower(),	*do_toupper(),
+ 	*do_sub(),	*do_gsub();
+ 
+ /* Special functions for debugging */
+ #ifdef DEBUG
+ NODE *do_prvars(), *do_bp();
+ #endif
+ 
+ /* Tokentab is sorted ascii ascending order, so it can be binary searched. */
+ 
+ static struct token tokentab[] = {
+ 	{ "BEGIN",	Node_illegal,		LEX_BEGIN,	0,	0 },
+ 	{ "END",	Node_illegal,		LEX_END,	0,	0 },
+ 	{ "atan2",	Node_builtin,		LEX_BUILTIN,	0,	do_atan2 },
+ #ifdef DEBUG
+ 	{ "bp",		Node_builtin,		LEX_BUILTIN,	0,	do_bp },
+ #endif
+ 	{ "break",	Node_K_break,		LEX_BREAK,	0,	0 },
+ 	{ "close",	Node_builtin,		LEX_BUILTIN,	0,	do_close },
+ 	{ "continue",	Node_K_continue,	LEX_CONTINUE,	0,	0 },
+ 	{ "cos",	Node_builtin,		LEX_BUILTIN,	0,	do_cos },
+ 	{ "delete",	Node_K_delete,		LEX_DELETE,	0,	0 },
+ 	{ "do",		Node_K_do,		LEX_DO,		0,	0 },
+ 	{ "else",	Node_illegal,		LEX_ELSE,	0,	0 },
+ 	{ "exit",	Node_K_exit,		LEX_EXIT,	0,	0 },
+ 	{ "exp",	Node_builtin,		LEX_BUILTIN,	0,	do_exp },
+ 	{ "for",	Node_K_for,		LEX_FOR,	0,	0 },
+ 	{ "func",	Node_K_function,	LEX_FUNCTION,	0,	0 },
+ 	{ "function",	Node_K_function,	LEX_FUNCTION,	0,	0 },
+ 	{ "getline",	Node_K_getline,		LEX_GETLINE,	0,	0 },
+ 	{ "gsub",	Node_builtin,		LEX_BUILTIN,	0,	do_gsub },
+ 	{ "if",		Node_K_if,		LEX_IF,		0,	0 },
+ 	{ "in",		Node_illegal,		LEX_IN,		0,	0 },
+ 	{ "index",	Node_builtin,		LEX_BUILTIN,	0,	do_index },
+ 	{ "int",	Node_builtin,		LEX_BUILTIN,	0,	do_int },
+ 	{ "length",	Node_builtin,		LEX_LENGTH,	0,	do_length },
+ 	{ "log",	Node_builtin,		LEX_BUILTIN,	0,	do_log },
+ 	{ "match",	Node_builtin,		LEX_BUILTIN,	0,	do_match },
+ 	{ "next",	Node_K_next,		LEX_NEXT,	0,	0 },
+ 	{ "print",	Node_K_print,		LEX_PRINT,	0,	0 },
+ 	{ "printf",	Node_K_printf,		LEX_PRINTF,	0,	0 },
+ #ifdef DEBUG
+ 	{ "prvars",	Node_builtin,		LEX_BUILTIN,	0,	do_prvars },
+ #endif
+ 	{ "rand",	Node_builtin,		LEX_BUILTIN,	0,	do_rand },
+ 	{ "return",	Node_K_return,		LEX_RETURN,	0,	0 },
+ 	{ "sin",	Node_builtin,		LEX_BUILTIN,	0,	do_sin },
+ 	{ "split",	Node_builtin,		LEX_BUILTIN,	0,	do_split },
+ 	{ "sprintf",	Node_builtin,		LEX_BUILTIN,	0,	do_sprintf },
+ 	{ "sqrt",	Node_builtin,		LEX_BUILTIN,	0,	do_sqrt },
+ 	{ "srand",	Node_builtin,		LEX_BUILTIN,	0,	do_srand },
+ 	{ "sub",	Node_builtin,		LEX_BUILTIN,	0,	do_sub },
+ 	{ "substr",	Node_builtin,		LEX_BUILTIN,	0,	do_substr },
+ 	{ "system",	Node_builtin,		LEX_BUILTIN,	0,	do_system },
+ 	{ "tolower",	Node_builtin,		LEX_BUILTIN,	0,	do_tolower },
+ 	{ "toupper",	Node_builtin,		LEX_BUILTIN,	0,	do_toupper },
+ 	{ "while",	Node_K_while,		LEX_WHILE,	0,	0 },
+ };
+ 
+ static char *token_start;
+ 
+ /* VARARGS0 */
+ static void
+ yyerror(char * the_msg, ...)
+ {
+ 	va_list args;
+ 	char *mesg;
+ 	register char *ptr, *beg;
+ 	char *scan;
+ 
+ 	errcount++;
+ 	/* Find the current line in the input file */
+ 	if (! lexptr) {
+ 		beg = "(END OF FILE)";
+ 		ptr = beg + 13;
+ 	} else {
+ 		if (*lexptr == '\n' && lexptr != lexptr_begin)
+ 			--lexptr;
+ 		for (beg = lexptr; beg != lexptr_begin && *beg != '\n'; --beg)
+ 			;
+ 		/* NL isn't guaranteed */
+ 		for (ptr = lexptr; *ptr && *ptr != '\n'; ptr++)
+ 			;
+ 		if (beg != lexptr_begin)
+ 			beg++;
+ 	}
+ 	msg("syntax error near line %d:\n%.*s", lineno, ptr - beg, beg);
+ 	scan = beg;
+ 	while (scan < token_start)
+ 		if (*scan++ == '\t')
+ 			putc('\t', stderr);
+ 		else
+ 			putc(' ', stderr);
+ 	putc('^', stderr);
+ 	putc(' ', stderr);
+ 	va_start(args, the_msg);
+ 	mesg = va_arg(args, char *);
+ 	vfprintf(stderr, mesg, args);
+ 	va_end(args);
+ 	putc('\n', stderr);
+ 	exit(1);
+ }
+ 
+ /*
+  * Parse a C escape sequence.  STRING_PTR points to a variable containing a
+  * pointer to the string to parse.  That pointer is updated past the
+  * characters we use.  The value of the escape sequence is returned. 
+  *
+  * A negative value means the sequence \ newline was seen, which is supposed to
+  * be equivalent to nothing at all. 
+  *
+  * If \ is followed by a null character, we return a negative value and leave
+  * the string pointer pointing at the null character. 
+  *
+  * If \ is followed by 000, we return 0 and leave the string pointer after the
+  * zeros.  A value of 0 does not mean end of string.  
+  */
+ 
+ int
+ parse_escape(string_ptr)
+ char **string_ptr;
+ {
+ 	register int c = *(*string_ptr)++;
+ 	register int i;
+ 	register int count;
+ 
+ 	switch (c) {
+ 	case 'a':
+ 		return BELL;
+ 	case 'b':
+ 		return '\b';
+ 	case 'f':
+ 		return '\f';
+ 	case 'n':
+ 		return '\n';
+ 	case 'r':
+ 		return '\r';
+ 	case 't':
+ 		return '\t';
+ 	case 'v':
+ 		return '\v';
+ 	case '\n':
+ 		return -2;
+ 	case 0:
+ 		(*string_ptr)--;
+ 		return -1;
+ 	case '0':
+ 	case '1':
+ 	case '2':
+ 	case '3':
+ 	case '4':
+ 	case '5':
+ 	case '6':
+ 	case '7':
+ 		i = c - '0';
+ 		count = 0;
+ 		while (++count < 3) {
+ 			if ((c = *(*string_ptr)++) >= '0' && c <= '7') {
+ 				i *= 8;
+ 				i += c - '0';
+ 			} else {
+ 				(*string_ptr)--;
+ 				break;
+ 			}
+ 		}
+ 		return i;
+ 	case 'x':
+ 		i = 0;
+ 		while (1) {
+ 			if (isxdigit((c = *(*string_ptr)++))) {
+ 				if (isdigit(c))
+ 					i += c - '0';
+ 				else if (isupper(c))
+ 					i += c - 'A' + 10;
+ 				else
+ 					i += c - 'a' + 10;
+ 			} else {
+ 				(*string_ptr)--;
+ 				break;
+ 			}
+ 		}
+ 		return i;
+ 	default:
+ 		return c;
+ 	}
+ }
+ 
+ /*
+  * Read the input and turn it into tokens. Input is now read from a file
+  * instead of from malloc'ed memory. The main program takes a program
+  * passed as a command line argument and writes it to a temp file. Otherwise
+  * the file name is made available in an external variable.
+  */
+ 
+ static int
+ yylex()
+ {
+ 	register int c;
+ 	register int namelen;
+ 	register char *tokstart;
+ 	char *tokkey;
+ 	static did_newline = 0;	/* the grammar insists that actions end
+ 				 * with newlines.  This was easier than
+ 				 * hacking the grammar. */
+ 	int seen_e = 0;		/* These are for numbers */
+ 	int seen_point = 0;
+ 	int esc_seen;
+ 	extern char **sourcefile;
+ 	extern int tempsource, numfiles;
+ 	static int file_opened = 0;
+ 	static FILE *fin;
+ 	static char cbuf[BUFSIZ];
+ 	int low, mid, high;
+ #ifdef DEBUG
+ 	extern int debugging;
+ #endif
+ 
+ 	if (! file_opened) {
+ 		file_opened = 1;
+ #ifdef DEBUG
+ 		if (debugging) {
+ 			int i;
+ 
+ 			for (i = 0; i <= numfiles; i++)
+ 				fprintf (stderr, "sourcefile[%d] = %s\n", i,
+ 						sourcefile[i]);
+ 		}
+ #endif
+ 	nextfile:
+ 		if ((fin = pathopen (sourcefile[++curinfile])) == NULL)
+ 			fatal("cannot open `%s' for reading (%s)",
+ 				sourcefile[curinfile],
+ 				strerror(errno));
+ 		*(lexptr = cbuf) = '\0';
+ 		/*
+ 		 * immediately unlink the tempfile so that it will
+ 		 * go away cleanly if we bomb.
+ 		 */
+ 		if (tempsource && curinfile == 0)
+ 			(void) unlink (sourcefile[curinfile]);
+ 	}
+ 
+ retry:
+ 	if (! *lexptr)
+ 		if (fgets (cbuf, sizeof cbuf, fin) == NULL) {
+ 			if (fin != NULL)
+ 				fclose (fin);	/* be neat and clean */
+ 			if (curinfile < numfiles)
+ 				goto nextfile;
+ 			return 0;
+ 		} else
+ 			lexptr = lexptr_begin = cbuf;
+ 
+ 	if (want_regexp) {
+ 		int in_brack = 0;
+ 
+ 		want_regexp = 0;
+ 		token_start = tokstart = lexptr;
+ 		while (c = *lexptr++) {
+ 			switch (c) {
+ 			case '[':
+ 				in_brack = 1;
+ 				break;
+ 			case ']':
+ 				in_brack = 0;
+ 				break;
+ 			case '\\':
+ 				if (*lexptr++ == '\0') {
+ 					yyerror("unterminated regexp ends with \\");
+ 					return ERROR;
+ 				} else if (lexptr[-1] == '\n')
+ 					goto retry;
+ 				break;
+ 			case '/':	/* end of the regexp */
+ 				if (in_brack)
+ 					break;
+ 
+ 				lexptr--;
+ 				yylval.sval = tokstart;
+ 				return REGEXP;
+ 			case '\n':
+ 				lineno++;
+ 			case '\0':
+ 				lexptr--;	/* so error messages work */
+ 				yyerror("unterminated regexp");
+ 				return ERROR;
+ 			}
+ 		}
+ 	}
+ 
+ 	if (*lexptr == '\n') {
+ 		lexptr++;
+ 		lineno++;
+ 		return NEWLINE;
+ 	}
+ 
+ 	while (*lexptr == ' ' || *lexptr == '\t')
+ 		lexptr++;
+ 
+ 	token_start = tokstart = lexptr;
+ 
+ 	switch (c = *lexptr++) {
+ 	case 0:
+ 		return 0;
+ 
+ 	case '\n':
+ 		lineno++;
+ 		return NEWLINE;
+ 
+ 	case '#':		/* it's a comment */
+ 		while (*lexptr != '\n' && *lexptr != '\0')
+ 			lexptr++;
+ 		goto retry;
+ 
+ 	case '\\':
+ 		if (*lexptr == '\n') {
+ 			lineno++;
+ 			lexptr++;
+ 			goto retry;
+ 		} else
+ 			break;
+ 	case ')':
+ 	case ']':
+ 	case '(':	
+ 	case '[':
+ 	case '$':
+ 	case ';':
+ 	case ':':
+ 	case '?':
+ 
+ 		/*
+ 		 * set node type to ILLEGAL because the action should set it
+ 		 * to the right thing 
+ 		 */
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '{':
+ 	case ',':
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '*':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_assign_times;
+ 			lexptr++;
+ 			return ASSIGNOP;
+ 		} else if (*lexptr == '*') {	/* make ** and **= aliases
+ 						 * for ^ and ^= */
+ 			if (lexptr[1] == '=') {
+ 				yylval.nodetypeval = Node_assign_exp;
+ 				lexptr += 2;
+ 				return ASSIGNOP;
+ 			} else {
+ 				yylval.nodetypeval = Node_illegal;
+ 				lexptr++;
+ 				return '^';
+ 			}
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '/':
+ 		if (want_assign && *lexptr == '=') {
+ 			yylval.nodetypeval = Node_assign_quotient;
+ 			lexptr++;
+ 			return ASSIGNOP;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '%':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_assign_mod;
+ 			lexptr++;
+ 			return ASSIGNOP;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '^':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_assign_exp;
+ 			lexptr++;
+ 			return ASSIGNOP;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '+':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_assign_plus;
+ 			lexptr++;
+ 			return ASSIGNOP;
+ 		}
+ 		if (*lexptr == '+') {
+ 			yylval.nodetypeval = Node_illegal;
+ 			lexptr++;
+ 			return INCREMENT;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '!':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_notequal;
+ 			lexptr++;
+ 			return RELOP;
+ 		}
+ 		if (*lexptr == '~') {
+ 			yylval.nodetypeval = Node_nomatch;
+ 			lexptr++;
+ 			return MATCHOP;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '<':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_leq;
+ 			lexptr++;
+ 			return RELOP;
+ 		}
+ 		yylval.nodetypeval = Node_less;
+ 		return c;
+ 
+ 	case '=':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_equal;
+ 			lexptr++;
+ 			return RELOP;
+ 		}
+ 		yylval.nodetypeval = Node_assign;
+ 		return ASSIGNOP;
+ 
+ 	case '>':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_geq;
+ 			lexptr++;
+ 			return RELOP;
+ 		} else if (*lexptr == '>') {
+ 			yylval.nodetypeval = Node_redirect_append;
+ 			lexptr++;
+ 			return APPEND_OP;
+ 		}
+ 		yylval.nodetypeval = Node_greater;
+ 		return c;
+ 
+ 	case '~':
+ 		yylval.nodetypeval = Node_match;
+ 		return MATCHOP;
+ 
+ 	case '}':
+ 		/*
+ 		 * Added did newline stuff.  Easier than
+ 		 * hacking the grammar
+ 		 */
+ 		if (did_newline) {
+ 			did_newline = 0;
+ 			return c;
+ 		}
+ 		did_newline++;
+ 		--lexptr;
+ 		return NEWLINE;
+ 
+ 	case '"':
+ 		esc_seen = 0;
+ 		while (*lexptr != '\0') {
+ 			switch (*lexptr++) {
+ 			case '\\':
+ 				esc_seen = 1;
+ 				if (*lexptr == '\n')
+ 					yyerror("newline in string");
+ 				if (*lexptr++ != '\0')
+ 					break;
+ 				/* fall through */
+ 			case '\n':
+ 				lexptr--;
+ 				yyerror("unterminated string");
+ 				return ERROR;
+ 			case '"':
+ 				yylval.nodeval = make_str_node(tokstart + 1,
+ 						lexptr-tokstart-2, esc_seen);
+ 				yylval.nodeval->flags |= PERM;
+ 				return YSTRING;
+ 			}
+ 		}
+ 		return ERROR;
+ 
+ 	case '-':
+ 		if (*lexptr == '=') {
+ 			yylval.nodetypeval = Node_assign_minus;
+ 			lexptr++;
+ 			return ASSIGNOP;
+ 		}
+ 		if (*lexptr == '-') {
+ 			yylval.nodetypeval = Node_illegal;
+ 			lexptr++;
+ 			return DECREMENT;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 
+ 	case '0':
+ 	case '1':
+ 	case '2':
+ 	case '3':
+ 	case '4':
+ 	case '5':
+ 	case '6':
+ 	case '7':
+ 	case '8':
+ 	case '9':
+ 	case '.':
+ 		/* It's a number */
+ 		for (namelen = 0; (c = tokstart[namelen]) != '\0'; namelen++) {
+ 			switch (c) {
+ 			case '.':
+ 				if (seen_point)
+ 					goto got_number;
+ 				++seen_point;
+ 				break;
+ 			case 'e':
+ 			case 'E':
+ 				if (seen_e)
+ 					goto got_number;
+ 				++seen_e;
+ 				if (tokstart[namelen + 1] == '-' ||
+ 				    tokstart[namelen + 1] == '+')
+ 					namelen++;
+ 				break;
+ 			case '0':
+ 			case '1':
+ 			case '2':
+ 			case '3':
+ 			case '4':
+ 			case '5':
+ 			case '6':
+ 			case '7':
+ 			case '8':
+ 			case '9':
+ 				break;
+ 			default:
+ 				goto got_number;
+ 			}
+ 		}
+ 
+ got_number:
+ 		lexptr = tokstart + namelen;
+ 		/*
+ 		yylval.nodeval = make_string(tokstart, namelen);
+ 		(void) force_number(yylval.nodeval);
+ 		*/
+ 		yylval.nodeval = make_number(atof(tokstart));
+ 		yylval.nodeval->flags |= PERM;
+ 		return NUMBER;
+ 
+ 	case '&':
+ 		if (*lexptr == '&') {
+ 			yylval.nodetypeval = Node_and;
+ 			while (c = *++lexptr) {
+ 				if (c == '#')
+ 					while ((c = *++lexptr) != '\n'
+ 					       && c != '\0')
+ 						;
+ 				if (c == '\n')
+ 					lineno++;
+ 				else if (! isspace(c))
+ 					break;
+ 			}
+ 			return LEX_AND;
+ 		}
+ 		return ERROR;
+ 
+ 	case '|':
+ 		if (*lexptr == '|') {
+ 			yylval.nodetypeval = Node_or;
+ 			while (c = *++lexptr) {
+ 				if (c == '#')
+ 					while ((c = *++lexptr) != '\n'
+ 					       && c != '\0')
+ 						;
+ 				if (c == '\n')
+ 					lineno++;
+ 				else if (! isspace(c))
+ 					break;
+ 			}
+ 			return LEX_OR;
+ 		}
+ 		yylval.nodetypeval = Node_illegal;
+ 		return c;
+ 	}
+ 
+ 	if (c != '_' && ! isalpha(c)) {
+ 		yyerror("Invalid char '%c' in expression\n", c);
+ 		return ERROR;
+ 	}
+ 
+ 	/* it's some type of name-type-thing.  Find its length */
+ 	for (namelen = 0; is_identchar(tokstart[namelen]); namelen++)
+ 		/* null */ ;
+ 	emalloc(tokkey, char *, namelen+1, "yylex");
+ 	memcpy(tokkey, tokstart, namelen);
+ 	tokkey[namelen] = '\0';
+ 
+ 	/* See if it is a special token.  */
+ 	low = 0;
+ 	high = (sizeof (tokentab) / sizeof (tokentab[0])) - 1;
+ 	while (low <= high) {
+ 		int i, c;
+ 
+ 		mid = (low + high) / 2;
+ 		c = *tokstart - tokentab[mid].operator[0];
+ 		i = c ? c : strcmp (tokkey, tokentab[mid].operator);
+ 
+ 		if (i < 0) {		/* token < mid */
+ 			high = mid - 1;
+ 		} else if (i > 0) {	/* token > mid */
+ 			low = mid + 1;
+ 		} else {
+ 			lexptr = tokstart + namelen;
+ 			if (strict && tokentab[mid].nostrict)
+ 				break;
+ 			if (tokentab[mid].class == LEX_BUILTIN
+ 			    || tokentab[mid].class == LEX_LENGTH)
+ 				yylval.ptrval = tokentab[mid].ptr;
+ 			else
+ 				yylval.nodetypeval = tokentab[mid].value;
+ 			return tokentab[mid].class;
+ 		}
+ 	}
+ 
+ 	/* It's a name.  See how long it is.  */
+ 	yylval.sval = tokkey;
+ 	lexptr = tokstart + namelen;
+ 	if (*lexptr == '(')
+ 		return FUNC_CALL;
+ 	else
+ 		return NAME;
+ }
+ 
+ #ifndef DEFPATH
+ #ifdef MSDOS
+ #define DEFPATH	"."
+ #define ENVSEP	';'
+ #else
+ #define DEFPATH	".:/usr/lib/awk:/usr/local/lib/awk"
+ #define ENVSEP	':'
+ #endif
+ #endif
+ 
+ static FILE *
+ pathopen (file)
+ char *file;
+ {
+ 	static char *savepath = DEFPATH;
+ 	static int first = 1;
+ 	char *awkpath, *cp;
+ 	char trypath[BUFSIZ];
+ 	FILE *fp;
+ #ifdef DEBUG
+ 	extern int debugging;
+ #endif
+ 	int fd;
+ 
+ 	if (strcmp (file, "-") == 0)
+ 		return (stdin);
+ 
+ 	if (strict)
+ 		return (fopen (file, "r"));
+ 
+ 	if (first) {
+ 		first = 0;
+ 		if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
+ 			savepath = awkpath;	/* used for restarting */
+ 	}
+ 	awkpath = savepath;
+ 
+ 	/* some kind of path name, no search */
+ #ifndef MSDOS
+ 	if (strchr (file, '/') != NULL)
+ #else
+ 	if (strchr (file, '/') != NULL || strchr (file, '\\') != NULL
+ 			|| strchr (file, ':') != NULL)
+ #endif
+ 		return ( (fd = devopen (file, "r")) >= 0 ?
+ 				fdopen(fd, "r") :
+ 				NULL);
+ 
+ 	do {
+ 		trypath[0] = '\0';
+ 		/* this should take into account limits on size of trypath */
+ 		for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
+ 			*cp++ = *awkpath++;
+ 
+ 		if (cp != trypath) {	/* nun-null element in path */
+ 			*cp++ = '/';
+ 			strcpy (cp, file);
+ 		} else
+ 			strcpy (trypath, file);
+ #ifdef DEBUG
+ 		if (debugging)
+ 			fprintf(stderr, "trying: %s\n", trypath);
+ #endif
+ 		if ((fd = devopen (trypath, "r")) >= 0
+ 		    && (fp = fdopen(fd, "r")) != NULL)
+ 			return (fp);
+ 
+ 		/* no luck, keep going */
+ 		if(*awkpath == ENVSEP && awkpath[1] != '\0')
+ 			awkpath++;	/* skip colon */
+ 	} while (*awkpath);
+ #ifdef MSDOS
+ 	/*
+ 	 * Under DOS (and probably elsewhere) you might have one of the awk
+ 	 * paths defined, WITHOUT the current working directory in it.
+ 	 * Therefore you should try to open the file in the current directory.
+ 	 */
+ 	return ( (fd = devopen(file, "r")) >= 0 ? fdopen(fd, "r") : NULL);
+ #else
+ 	return (NULL);
+ #endif
+ }
+ 
+ static NODE *
+ node_common(op)
+ NODETYPE op;
+ {
+ 	register NODE *r;
+ 	extern int numfiles;
+ 	extern int tempsource;
+ 	extern char **sourcefile;
+ 
+ 	r = newnode(op);
+ 	r->source_line = lineno;
+ 	if (numfiles > -1 && ! tempsource)
+ 		r->source_file = sourcefile[curinfile];
+ 	else
+ 		r->source_file = NULL;
+ 	return r;
+ }
+ 
+ /*
+  * This allocates a node with defined lnode and rnode. 
+  * This should only be used by yyparse+co while reading in the program 
+  */
+ NODE *
+ node(left, op, right)
+ NODE *left, *right;
+ NODETYPE op;
+ {
+ 	register NODE *r;
+ 
+ 	r = node_common(op);
+ 	r->lnode = left;
+ 	r->rnode = right;
+ 	return r;
+ }
+ 
+ /*
+  * This allocates a node with defined subnode and proc
+  * Otherwise like node()
+  */
+ static NODE *
+ snode(subn, op, procp)
+ NODETYPE op;
+ NODE *(*procp) ();
+ NODE *subn;
+ {
+ 	register NODE *r;
+ 
+ 	r = node_common(op);
+ 	r->subnode = subn;
+ 	r->proc = procp;
+ 	return r;
+ }
+ 
+ /*
+  * This allocates a Node_line_range node with defined condpair and
+  * zeroes the trigger word to avoid the temptation of assuming that calling
+  * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. 
+  */
+ /* Otherwise like node() */
+ static NODE *
+ mkrangenode(cpair)
+ NODE *cpair;
+ {
+ 	register NODE *r;
+ 
+ 	r = newnode(Node_line_range);
+ 	r->condpair = cpair;
+ 	r->triggered = 0;
+ 	return r;
+ }
+ 
+ /* Build a for loop */
+ static NODE *
+ make_for_loop(init, cond, incr)
+ NODE *init, *cond, *incr;
+ {
+ 	register FOR_LOOP_HEADER *r;
+ 	NODE *n;
+ 
+ 	emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
+ 	n = newnode(Node_illegal);
+ 	r->init = init;
+ 	r->cond = cond;
+ 	r->incr = incr;
+ 	n->sub.nodep.r.hd = r;
+ 	return n;
+ }
+ 
+ /*
+  * Install a name in the hash table specified, even if it is already there.
+  * Name stops with first non alphanumeric. Caller must check against
+  * redefinition if that is desired. 
+  */
+ NODE *
+ install(table, name, value)
+ NODE **table;
+ char *name;
+ NODE *value;
+ {
+ 	register NODE *hp;
+ 	register int len, bucket;
+ 	register char *p;
+ 
+ 	len = 0;
+ 	p = name;
+ 	while (is_identchar(*p))
+ 		p++;
+ 	len = p - name;
+ 
+ 	hp = newnode(Node_hashnode);
+ 	bucket = hashf(name, len, HASHSIZE);
+ 	hp->hnext = table[bucket];
+ 	table[bucket] = hp;
+ 	hp->hlength = len;
+ 	hp->hvalue = value;
+ 	emalloc(hp->hname, char *, len + 1, "install");
+ 	memcpy(hp->hname, name, len);
+ 	hp->hname[len] = '\0';
+ 	return hp->hvalue;
+ }
+ 
+ /*
+  * find the most recent hash node for name name (ending with first
+  * non-identifier char) installed by install 
+  */
+ NODE *
+ lookup(table, name)
+ NODE **table;
+ char *name;
+ {
+ 	register char *bp;
+ 	register NODE *bucket;
+ 	register int len;
+ 
+ 	for (bp = name; is_identchar(*bp); bp++)
+ 		;
+ 	len = bp - name;
+ 	bucket = table[hashf(name, len, HASHSIZE)];
+ 	while (bucket) {
+ 		if (bucket->hlength == len && STREQN(bucket->hname, name, len))
+ 			return bucket->hvalue;
+ 		bucket = bucket->hnext;
+ 	}
+ 	return NULL;
+ }
+ 
+ #define HASHSTEP(old, c) ((old << 1) + c)
+ #define MAKE_POS(v) (v & ~0x80000000)	/* make number positive */
+ 
+ /*
+  * return hash function on name.
+  */
+ static int
+ hashf(name, len, hashsize)
+ register char *name;
+ register int len;
+ int hashsize;
+ {
+ 	register int r = 0;
+ 
+ 	while (len--)
+ 		r = HASHSTEP(r, *name++);
+ 
+ 	r = MAKE_POS(r) % hashsize;
+ 	return r;
+ }
+ 
+ /*
+  * Add new to the rightmost branch of LIST.  This uses n^2 time, so we make
+  * a simple attempt at optimizing it.
+  */
+ static NODE *
+ append_right(list, new)
+ NODE *list, *new;
+ 
+ {
+ 	register NODE *oldlist;
+ 	static NODE *savefront = NULL, *savetail = NULL;
+ 
+ 	oldlist = list;
+ 	if (savefront == oldlist) {
+ 		savetail = savetail->rnode = new;
+ 		return oldlist;
+ 	} else
+ 		savefront = oldlist;
+ 	while (list->rnode != NULL)
+ 		list = list->rnode;
+ 	savetail = list->rnode = new;
+ 	return oldlist;
+ }
+ 
+ /*
+  * check if name is already installed;  if so, it had better have Null value,
+  * in which case def is added as the value. Otherwise, install name with def
+  * as value. 
+  */
+ static void
+ func_install(params, def)
+ NODE *params;
+ NODE *def;
+ {
+ 	NODE *r;
+ 
+ 	pop_params(params->rnode);
+ 	pop_var(params, 0);
+ 	r = lookup(variables, params->param);
+ 	if (r != NULL) {
+ 		fatal("function name `%s' previously defined", params->param);
+ 	} else
+ 		(void) install(variables, params->param,
+ 			node(params, Node_func, def));
+ }
+ 
+ static void
+ pop_var(np, freeit)
+ NODE *np;
+ int freeit;
+ {
+ 	register char *bp;
+ 	register NODE *bucket, **save;
+ 	register int len;
+ 	char *name;
+ 
+ 	name = np->param;
+ 	for (bp = name; is_identchar(*bp); bp++)
+ 		;
+ 	len = bp - name;
+ 	save = &(variables[hashf(name, len, HASHSIZE)]);
+ 	bucket = *save;
+ 	while (bucket != NULL) {
+ 	        NODE *next = bucket->hnext;
+ 	    
+ /*	for (bucket = *save; bucket; bucket = bucket->hnext) {
+ */
+ 	    
+ 		if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
+ 			*save = bucket->hnext;
+ 			save = &(bucket->hnext);
+ 			free(bucket->hname);
+ 			freenode(bucket);
+ 			if (freeit)
+ 				free(np->param);
+ 			return;
+ 		} else {
+ 			save = &(bucket->hnext);
+ 		}
+ 		bucket = next;
+ 	}
+ }
+ 
+ static void
+ pop_params(params)
+ NODE *params;
+ {
+ 	register NODE *np;
+ 
+ 	for (np = params; np != NULL; np = np->rnode)
+ 		pop_var(np, 1);
+ }
+ 
+ static NODE *
+ make_param(name)
+ char *name;
+ {
+ 	NODE *r;
+ 
+ 	r = newnode(Node_param_list);
+ 	r->param = name;
+ 	r->rnode = NULL;
+ 	r->param_cnt = param_counter++;
+ 	return (install(variables, name, r));
+ }
+ 
+ /* Name points to a variable name.  Make sure its in the symbol table */
+ NODE *
+ variable(name)
+ char *name;
+ {
+ 	register NODE *r;
+ 
+ 	if ((r = lookup(variables, name)) == NULL)
+ 		r = install(variables, name,
+ 			node(Nnull_string, Node_var, (NODE *) NULL));
+ 	return r;
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/builtin.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/builtin.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/builtin.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,1055 ----
+ /*
+  * builtin.c - Builtin functions and various utility procedures 
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ extern void srandom();
+ extern char *initstate();
+ extern char *setstate();
+ extern long random();
+ 
+ extern NODE **fields_arr;
+ 
+ static void get_one();
+ static void get_two();
+ static int get_three();
+ 
+ /* Builtin functions */
+ NODE *
+ do_exp(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	double d, res;
+ 	double exp();
+ 
+ 	get_one(tree, &tmp);
+ 	d = force_number(tmp);
+ 	free_temp(tmp);
+ 	errno = 0;
+ 	res = exp(d);
+ 	if (errno == ERANGE)
+ 		warning("exp argument %g is out of range", d);
+ 	return tmp_number((AWKNUM) res);
+ }
+ 
+ NODE *
+ do_index(tree)
+ NODE *tree;
+ {
+ 	NODE *s1, *s2;
+ 	register char *p1, *p2;
+ 	register int l1, l2;
+ 	long ret;
+ 
+ 
+ 	get_two(tree, &s1, &s2);
+ 	force_string(s1);
+ 	force_string(s2);
+ 	p1 = s1->stptr;
+ 	p2 = s2->stptr;
+ 	l1 = s1->stlen;
+ 	l2 = s2->stlen;
+ 	ret = 0;
+ 	if (! strict && IGNORECASE_node->var_value->numbr != 0.0) {
+ 		while (l1) {
+ 			if (casetable[*p1] == casetable[*p2]
+ 			    && strncasecmp(p1, p2, l2) == 0) {
+ 				ret = 1 + s1->stlen - l1;
+ 				break;
+ 			}
+ 			l1--;
+ 			p1++;
+ 		}
+ 	} else {
+ 		while (l1) {
+ 			if (STREQN(p1, p2, l2)) {
+ 				ret = 1 + s1->stlen - l1;
+ 				break;
+ 			}
+ 			l1--;
+ 			p1++;
+ 		}
+ 	}
+ 	free_temp(s1);
+ 	free_temp(s2);
+ 	return tmp_number((AWKNUM) ret);
+ }
+ 
+ NODE *
+ do_int(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	double floor();
+ 	double d;
+ 
+ 	get_one(tree, &tmp);
+ 	d = floor((double)force_number(tmp));
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) d);
+ }
+ 
+ NODE *
+ do_length(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	int len;
+ 
+ 	get_one(tree, &tmp);
+ 	len = force_string(tmp)->stlen;
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) len);
+ }
+ 
+ NODE *
+ do_log(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	double log();
+ 	double d, arg;
+ 
+ 	get_one(tree, &tmp);
+ 	arg = (double) force_number(tmp);
+ 	if (arg < 0.0)
+ 		warning("log called with negative argument %g", arg);
+ 	d = log(arg);
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) d);
+ }
+ 
+ /*
+  * Note that the output buffer cannot be static because sprintf may get
+  * called recursively by force_string.  Hence the wasteful alloca calls 
+  */
+ 
+ /* %e and %f formats are not properly implemented.  Someone should fix them */
+ NODE *
+ do_sprintf(tree)
+ NODE *tree;
+ {
+ #define bchunk(s,l) if(l) {\
+     while((l)>ofre) {\
+       char *tmp;\
+       tmp=(char *)alloca(osiz*2);\
+       memcpy(tmp,obuf,olen);\
+       obuf=tmp;\
+       ofre+=osiz;\
+       osiz*=2;\
+     }\
+     memcpy(obuf+olen,s,(l));\
+     olen+=(l);\
+     ofre-=(l);\
+   }
+ 
+ 	/* Is there space for something L big in the buffer? */
+ #define chksize(l)  if((l)>ofre) {\
+     char *tmp;\
+     tmp=(char *)alloca(osiz*2);\
+     memcpy(tmp,obuf,olen);\
+     obuf=tmp;\
+     ofre+=osiz;\
+     osiz*=2;\
+   }
+ 
+ 	/*
+ 	 * Get the next arg to be formatted.  If we've run out of args,
+ 	 * return "" (Null string) 
+ 	 */
+ #define parse_next_arg() {\
+   if(!carg) arg= Nnull_string;\
+   else {\
+   	get_one(carg,&arg);\
+ 	carg=carg->rnode;\
+   }\
+  }
+ 
+ 	char *obuf;
+ 	int osiz, ofre, olen;
+ 	static char chbuf[] = "0123456789abcdef";
+ 	static char sp[] = " ";
+ 	char *s0, *s1;
+ 	int n0;
+ 	NODE *sfmt, *arg;
+ 	register NODE *carg;
+ 	long fw, prec, lj, alt, big;
+ 	long *cur;
+ 	long val;
+ #ifdef sun386			/* Can't cast unsigned (int/long) from ptr->value */
+ 	long tmp_uval;		/* on 386i 4.0.1 C compiler -- it just hangs */
+ #endif
+ 	unsigned long uval;
+ 	int sgn;
+ 	int base;
+ 	char cpbuf[30];		/* if we have numbers bigger than 30 */
+ 	char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
+ 	char *cp;
+ 	char *fill;
+ 	double tmpval;
+ 	char *pr_str;
+ 	int ucasehex = 0;
+ 	extern char *gcvt();
+ 
+ 
+ 	obuf = (char *) alloca(120);
+ 	osiz = 120;
+ 	ofre = osiz;
+ 	olen = 0;
+ 	get_one(tree, &sfmt);
+ 	sfmt = force_string(sfmt);
+ 	carg = tree->rnode;
+ 	for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
+ 		if (*s1 != '%') {
+ 			s1++;
+ 			continue;
+ 		}
+ 		bchunk(s0, s1 - s0);
+ 		s0 = s1;
+ 		cur = &fw;
+ 		fw = 0;
+ 		prec = 0;
+ 		lj = alt = big = 0;
+ 		fill = sp;
+ 		cp = cend;
+ 		s1++;
+ 
+ retry:
+ 		--n0;
+ 		switch (*s1++) {
+ 		case '%':
+ 			bchunk("%", 1);
+ 			s0 = s1;
+ 			break;
+ 
+ 		case '0':
+ 			if (fill != sp || lj)
+ 				goto lose;
+ 			if (cur == &fw)
+ 				fill = "0";	/* FALL through */
+ 		case '1':
+ 		case '2':
+ 		case '3':
+ 		case '4':
+ 		case '5':
+ 		case '6':
+ 		case '7':
+ 		case '8':
+ 		case '9':
+ 			if (cur == 0)
+ 				goto lose;
+ 			*cur = s1[-1] - '0';
+ 			while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+ 				--n0;
+ 				*cur = *cur * 10 + *s1++ - '0';
+ 			}
+ 			goto retry;
+ #ifdef not_yet
+ 		case ' ':		/* print ' ' or '-' */
+ 		case '+':		/* print '+' or '-' */
+ #endif
+ 		case '-':
+ 			if (lj || fill != sp)
+ 				goto lose;
+ 			lj++;
+ 			goto retry;
+ 		case '.':
+ 			if (cur != &fw)
+ 				goto lose;
+ 			cur = ≺
+ 			goto retry;
+ 		case '#':
+ 			if (alt)
+ 				goto lose;
+ 			alt++;
+ 			goto retry;
+ 		case 'l':
+ 			if (big)
+ 				goto lose;
+ 			big++;
+ 			goto retry;
+ 		case 'c':
+ 			parse_next_arg();
+ 			if (arg->flags & NUMERIC) {
+ #ifdef sun386
+ 				tmp_uval = arg->numbr; 
+ 				uval= (unsigned long) tmp_uval;
+ #else
+ 				uval = (unsigned long) arg->numbr;
+ #endif
+ 				cpbuf[0] = uval;
+ 				prec = 1;
+ 				pr_str = cpbuf;
+ 				goto dopr_string;
+ 			}
+ 			if (! prec)
+ 				prec = 1;
+ 			else if (prec > arg->stlen)
+ 				prec = arg->stlen;
+ 			pr_str = arg->stptr;
+ 			goto dopr_string;
+ 		case 's':
+ 			parse_next_arg();
+ 			arg = force_string(arg);
+ 			if (!prec || prec > arg->stlen)
+ 				prec = arg->stlen;
+ 			pr_str = arg->stptr;
+ 
+ 	dopr_string:
+ 			if (fw > prec && !lj) {
+ 				while (fw > prec) {
+ 					bchunk(sp, 1);
+ 					fw--;
+ 				}
+ 			}
+ 			bchunk(pr_str, (int) prec);
+ 			if (fw > prec) {
+ 				while (fw > prec) {
+ 					bchunk(sp, 1);
+ 					fw--;
+ 				}
+ 			}
+ 			s0 = s1;
+ 			free_temp(arg);
+ 			break;
+ 		case 'd':
+ 		case 'i':
+ 			parse_next_arg();
+ 			val = (long) force_number(arg);
+ 			free_temp(arg);
+ 			if (val < 0) {
+ 				sgn = 1;
+ 				val = -val;
+ 			} else
+ 				sgn = 0;
+ 			do {
+ 				*--cp = '0' + val % 10;
+ 				val /= 10;
+ 			} while (val);
+ 			if (sgn)
+ 				*--cp = '-';
+ 			if (prec > fw)
+ 				fw = prec;
+ 			prec = cend - cp;
+ 			if (fw > prec && !lj) {
+ 				if (fill != sp && *cp == '-') {
+ 					bchunk(cp, 1);
+ 					cp++;
+ 					prec--;
+ 					fw--;
+ 				}
+ 				while (fw > prec) {
+ 					bchunk(fill, 1);
+ 					fw--;
+ 				}
+ 			}
+ 			bchunk(cp, (int) prec);
+ 			if (fw > prec) {
+ 				while (fw > prec) {
+ 					bchunk(fill, 1);
+ 					fw--;
+ 				}
+ 			}
+ 			s0 = s1;
+ 			break;
+ 		case 'u':
+ 			base = 10;
+ 			goto pr_unsigned;
+ 		case 'o':
+ 			base = 8;
+ 			goto pr_unsigned;
+ 		case 'X':
+ 			ucasehex = 1;
+ 		case 'x':
+ 			base = 16;
+ 			goto pr_unsigned;
+ 	pr_unsigned:
+ 			parse_next_arg();
+ 			uval = (unsigned long) force_number(arg);
+ 			free_temp(arg);
+ 			do {
+ 				*--cp = chbuf[uval % base];
+ 				if (ucasehex && isalpha(*cp))
+ 					*cp = toupper(*cp);
+ 				uval /= base;
+ 			} while (uval);
+ 			if (alt && (base == 8 || base == 16)) {
+ 				if (base == 16) {
+ 					if (ucasehex)
+ 						*--cp = 'X';
+ 					else
+ 						*--cp = 'x';
+ 				}
+ 				*--cp = '0';
+ 			}
+ 			prec = cend - cp;
+ 			if (fw > prec && !lj) {
+ 				while (fw > prec) {
+ 					bchunk(fill, 1);
+ 					fw--;
+ 				}
+ 			}
+ 			bchunk(cp, (int) prec);
+ 			if (fw > prec) {
+ 				while (fw > prec) {
+ 					bchunk(fill, 1);
+ 					fw--;
+ 				}
+ 			}
+ 			s0 = s1;
+ 			break;
+ 		case 'g':
+ 			parse_next_arg();
+ 			tmpval = force_number(arg);
+ 			free_temp(arg);
+ 			if (prec == 0)
+ 				prec = 13;
+ 			(void) gcvt(tmpval, (int) prec, cpbuf);
+ 			prec = strlen(cpbuf);
+ 			cp = cpbuf;
+ 			if (fw > prec && !lj) {
+ 				if (fill != sp && *cp == '-') {
+ 					bchunk(cp, 1);
+ 					cp++;
+ 					prec--;
+ 				}	/* Deal with .5 as 0.5 */
+ 				if (fill == sp && *cp == '.') {
+ 					--fw;
+ 					while (--fw >= prec) {
+ 						bchunk(fill, 1);
+ 					}
+ 					bchunk("0", 1);
+ 				} else
+ 					while (fw-- > prec)
+ 						bchunk(fill, 1);
+ 			} else {/* Turn .5 into 0.5 */
+ 				/* FOO */
+ 				if (*cp == '.' && fill == sp) {
+ 					bchunk("0", 1);
+ 					--fw;
+ 				}
+ 			}
+ 			bchunk(cp, (int) prec);
+ 			if (fw > prec)
+ 				while (fw-- > prec)
+ 					bchunk(fill, 1);
+ 			s0 = s1;
+ 			break;
+ 		case 'f':
+ 			parse_next_arg();
+ 			tmpval = force_number(arg);
+ 			free_temp(arg);
+ 			chksize(fw + prec + 5);	/* 5==slop */
+ 
+ 			cp = cpbuf;
+ 			*cp++ = '%';
+ 			if (lj)
+ 				*cp++ = '-';
+ 			if (fill != sp)
+ 				*cp++ = '0';
+ 			if (cur != &fw) {
+ 				(void) strcpy(cp, "*.*f");
+ 				(void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
+ 			} else {
+ 				(void) strcpy(cp, "*f");
+ 				(void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
+ 			}
+ 			ofre -= strlen(obuf + olen);
+ 			olen += strlen(obuf + olen);	/* There may be nulls */
+ 			s0 = s1;
+ 			break;
+ 		case 'e':
+ 			parse_next_arg();
+ 			tmpval = force_number(arg);
+ 			free_temp(arg);
+ 			chksize(fw + prec + 5);	/* 5==slop */
+ 			cp = cpbuf;
+ 			*cp++ = '%';
+ 			if (lj)
+ 				*cp++ = '-';
+ 			if (fill != sp)
+ 				*cp++ = '0';
+ 			if (cur != &fw) {
+ 				(void) strcpy(cp, "*.*e");
+ 				(void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
+ 			} else {
+ 				(void) strcpy(cp, "*e");
+ 				(void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
+ 			}
+ 			ofre -= strlen(obuf + olen);
+ 			olen += strlen(obuf + olen);	/* There may be nulls */
+ 			s0 = s1;
+ 			break;
+ 
+ 		default:
+ 	lose:
+ 			break;
+ 		}
+ 	}
+ 	bchunk(s0, s1 - s0);
+ 	free_temp(sfmt);
+ 	return tmp_string(obuf, olen);
+ }
+ 
+ void
+ do_printf(tree)
+ NODE *tree;
+ {
+ 	struct redirect *rp = NULL;
+ 	register FILE *fp = stdout;
+ 	int errflg = 0;		/* not used, sigh */
+ 
+ 	if (tree->rnode) {
+ 		rp = redirect(tree->rnode, &errflg);
+ 		if (rp)
+ 			fp = rp->fp;
+ 	}
+ 	if (fp)
+ 		print_simple(do_sprintf(tree->lnode), fp);
+ 	if (rp && (rp->flag & RED_NOBUF))
+ 		fflush(fp);
+ }
+ 
+ NODE *
+ do_sqrt(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	double sqrt();
+ 	double d, arg;
+ 
+ 	get_one(tree, &tmp);
+ 	arg = (double) force_number(tmp);
+ 	if (arg < 0.0)
+ 		warning("sqrt called with negative argument %g", arg);
+ 	d = sqrt(arg);
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) d);
+ }
+ 
+ NODE *
+ do_substr(tree)
+ NODE *tree;
+ {
+ 	NODE *t1, *t2, *t3;
+ 	NODE *r;
+ 	register int indx, length;
+ 
+ 	t1 = t2 = t3 = NULL;
+ 	length = -1;
+ 	if (get_three(tree, &t1, &t2, &t3) == 3)
+ 		length = (int) force_number(t3);
+ 	indx = (int) force_number(t2) - 1;
+ 	t1 = force_string(t1);
+ 	if (length == -1)
+ 		length = t1->stlen;
+ 	if (indx < 0)
+ 		indx = 0;
+ 	if (indx >= t1->stlen || length <= 0) {
+ 		if (t3)
+ 			free_temp(t3);
+ 		free_temp(t2);
+ 		free_temp(t1);
+ 		return Nnull_string;
+ 	}
+ 	if (indx + length > t1->stlen)
+ 		length = t1->stlen - indx;
+ 	if (t3)
+ 		free_temp(t3);
+ 	free_temp(t2);
+ 	r =  tmp_string(t1->stptr + indx, length);
+ 	free_temp(t1);
+ 	return r;
+ }
+ 
+ NODE *
+ do_system(tree)
+ NODE *tree;
+ {
+ #if defined(unix) || defined(MSDOS) /* || defined(gnu) */
+ 	NODE *tmp;
+ 	int ret;
+ 
+ 	(void) flush_io ();	/* so output is synchronous with gawk's */
+ 	get_one(tree, &tmp);
+ 	ret = system(force_string(tmp)->stptr);
+ 	ret = (ret >> 8) & 0xff;
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) ret);
+ #else
+ 	fatal("the \"system\" function is not supported.");
+ 	/* NOTREACHED */
+ #endif
+ }
+ 
+ void 
+ do_print(tree)
+ register NODE *tree;
+ {
+ 	struct redirect *rp = NULL;
+ 	register FILE *fp = stdout;
+ 	int errflg = 0;		/* not used, sigh */
+ 
+ 	if (tree->rnode) {
+ 		rp = redirect(tree->rnode, &errflg);
+ 		if (rp)
+ 			fp = rp->fp;
+ 	}
+ 	if (!fp)
+ 		return;
+ 	tree = tree->lnode;
+ 	if (!tree)
+ 		tree = WHOLELINE;
+ 	if (tree->type != Node_expression_list) {
+ 		if (!(tree->flags & STR))
+ 			cant_happen();
+ 		print_simple(tree, fp);
+ 	} else {
+ 		while (tree) {
+ 			print_simple(force_string(tree_eval(tree->lnode)), fp);
+ 			tree = tree->rnode;
+ 			if (tree)
+ 				print_simple(OFS_node->var_value, fp);
+ 		}
+ 	}
+ 	print_simple(ORS_node->var_value, fp);
+ 	if (rp && (rp->flag & RED_NOBUF))
+ 		fflush(fp);
+ }
+ 
+ NODE *
+ do_tolower(tree)
+ NODE *tree;
+ {
+ 	NODE *t1, *t2;
+ 	register char *cp, *cp2;
+ 
+ 	get_one(tree, &t1);
+ 	t1 = force_string(t1);
+ 	t2 = tmp_string(t1->stptr, t1->stlen);
+ 	for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
+ 		if (isupper(*cp))
+ 			*cp = tolower(*cp);
+ 	free_temp(t1);
+ 	return t2;
+ }
+ 
+ NODE *
+ do_toupper(tree)
+ NODE *tree;
+ {
+ 	NODE *t1, *t2;
+ 	register char *cp;
+ 
+ 	get_one(tree, &t1);
+ 	t1 = force_string(t1);
+ 	t2 = tmp_string(t1->stptr, t1->stlen);
+ 	for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
+ 		if (islower(*cp))
+ 			*cp = toupper(*cp);
+ 	free_temp(t1);
+ 	return t2;
+ }
+ 
+ /*
+  * Get the arguments to functions.  No function cares if you give it too many
+  * args (they're ignored).  Only a few fuctions complain about being given
+  * too few args.  The rest have defaults.
+  */
+ 
+ static void
+ get_one(tree, res)
+ NODE *tree, **res;
+ {
+ 	if (!tree) {
+ 		*res = WHOLELINE;
+ 		return;
+ 	}
+ 	*res = tree_eval(tree->lnode);
+ }
+ 
+ static void
+ get_two(tree, res1, res2)
+ NODE *tree, **res1, **res2;
+ {
+ 	if (!tree) {
+ 		*res1 = WHOLELINE;
+ 		return;
+ 	}
+ 	*res1 = tree_eval(tree->lnode);
+ 	if (!tree->rnode)
+ 		return;
+ 	tree = tree->rnode;
+ 	*res2 = tree_eval(tree->lnode);
+ }
+ 
+ static int
+ get_three(tree, res1, res2, res3)
+ NODE *tree, **res1, **res2, **res3;
+ {
+ 	if (!tree) {
+ 		*res1 = WHOLELINE;
+ 		return 0;
+ 	}
+ 	*res1 = tree_eval(tree->lnode);
+ 	if (!tree->rnode)
+ 		return 1;
+ 	tree = tree->rnode;
+ 	*res2 = tree_eval(tree->lnode);
+ 	if (!tree->rnode)
+ 		return 2;
+ 	tree = tree->rnode;
+ 	*res3 = tree_eval(tree->lnode);
+ 	return 3;
+ }
+ 
+ int
+ a_get_three(tree, res1, res2, res3)
+ NODE *tree, **res1, **res2, **res3;
+ {
+ 	if (!tree) {
+ 		*res1 = WHOLELINE;
+ 		return 0;
+ 	}
+ 	*res1 = tree_eval(tree->lnode);
+ 	if (!tree->rnode)
+ 		return 1;
+ 	tree = tree->rnode;
+ 	*res2 = tree->lnode;
+ 	if (!tree->rnode)
+ 		return 2;
+ 	tree = tree->rnode;
+ 	*res3 = tree_eval(tree->lnode);
+ 	return 3;
+ }
+ 
+ void
+ print_simple(tree, fp)
+ NODE *tree;
+ FILE *fp;
+ {
+ 	if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen)
+ 		warning("fwrite: %s", strerror(errno));
+ 	free_temp(tree);
+ }
+ 
+ NODE *
+ do_atan2(tree)
+ NODE *tree;
+ {
+ 	NODE *t1, *t2;
+ 	extern double atan2();
+ 	double d1, d2;
+ 
+ 	get_two(tree, &t1, &t2);
+ 	d1 = force_number(t1);
+ 	d2 = force_number(t2);
+ 	free_temp(t1);
+ 	free_temp(t2);
+ 	return tmp_number((AWKNUM) atan2(d1, d2));
+ }
+ 
+ NODE *
+ do_sin(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	extern double sin();
+ 	double d;
+ 
+ 	get_one(tree, &tmp);
+ 	d = sin((double)force_number(tmp));
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) d);
+ }
+ 
+ NODE *
+ do_cos(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	extern double cos();
+ 	double d;
+ 
+ 	get_one(tree, &tmp);
+ 	d = cos((double)force_number(tmp));
+ 	free_temp(tmp);
+ 	return tmp_number((AWKNUM) d);
+ }
+ 
+ static int firstrand = 1;
+ static char state[256];
+ 
+ #define	MAXLONG	2147483647	/* maximum value for long int */
+ 
+ /* ARGSUSED */
+ NODE *
+ do_rand(tree)
+ NODE *tree;
+ {
+ 	if (firstrand) {
+ 		(void) initstate((unsigned) 1, state, sizeof state);
+ 		srandom(1);
+ 		firstrand = 0;
+ 	}
+ 	return tmp_number((AWKNUM) random() / MAXLONG);
+ }
+ 
+ NODE *
+ do_srand(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	static long save_seed = 1;
+ 	long ret = save_seed;	/* SVR4 awk srand returns previous seed */
+ 	extern long time();
+ 
+ 	if (firstrand)
+ 		(void) initstate((unsigned) 1, state, sizeof state);
+ 	else
+ 		(void) setstate(state);
+ 
+ 	if (!tree)
+ 		srandom((int) (save_seed = time((long *) 0)));
+ 	else {
+ 		get_one(tree, &tmp);
+ 		srandom((int) (save_seed = (long) force_number(tmp)));
+ 		free_temp(tmp);
+ 	}
+ 	firstrand = 0;
+ 	return tmp_number((AWKNUM) ret);
+ }
+ 
+ NODE *
+ do_match(tree)
+ NODE *tree;
+ {
+ 	NODE *t1;
+ 	int rstart;
+ 	struct re_registers reregs;
+ 	struct re_pattern_buffer *rp;
+ 	int need_to_free = 0;
+ 
+ 	t1 = force_string(tree_eval(tree->lnode));
+ 	tree = tree->rnode;
+ 	if (tree == NULL || tree->lnode == NULL)
+ 		fatal("match called with only one argument");
+ 	tree = tree->lnode;
+ 	if (tree->type == Node_regex) {
+ 		rp = tree->rereg;
+ 		if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
+ 		    ^ (tree->re_case != 0))) {
+ 			/* recompile since case sensitivity differs */
+ 			rp = tree->rereg =
+ 				mk_re_parse(tree->re_text,
+ 				(IGNORECASE_node->var_value->numbr != 0));
+ 			tree->re_case =
+ 				(IGNORECASE_node->var_value->numbr != 0);
+ 		}
+ 	} else {
+ 		need_to_free = 1;
+ 		rp = make_regexp(force_string(tree_eval(tree)),
+ 				(IGNORECASE_node->var_value->numbr != 0));
+ 		if (rp == NULL)
+ 			cant_happen();
+ 	}
+ 	rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
+ 	free_temp(t1);
+ 	if (rstart >= 0) {
+ 		rstart++;	/* 1-based indexing */
+ 		/* RSTART set to rstart below */
+ 		RLENGTH_node->var_value->numbr =
+ 			(AWKNUM) (reregs.end[0] - reregs.start[0]);
+ 	} else {
+ 		/*
+ 		 * Match failed. Set RSTART to 0, RLENGTH to -1.
+ 		 * Return the value of RSTART.
+ 		 */
+ 		rstart = 0;	/* used as return value */
+ 		RLENGTH_node->var_value->numbr = -1.0;
+ 	}
+ 	RSTART_node->var_value->numbr = (AWKNUM) rstart;
+ 	if (need_to_free) {
+ 		free(rp->buffer);
+ 		free(rp->fastmap);
+ 		free((char *) rp);
+ 	}
+ 	return tmp_number((AWKNUM) rstart);
+ }
+ 
+ static NODE *
+ sub_common(tree, global)
+ NODE *tree;
+ int global;
+ {
+ 	register int len;
+ 	register char *scan;
+ 	register char *bp, *cp;
+ 	int search_start = 0;
+ 	int match_length;
+ 	int matches = 0;
+ 	char *buf;
+ 	struct re_pattern_buffer *rp;
+ 	NODE *s;		/* subst. pattern */
+ 	NODE *t;		/* string to make sub. in; $0 if none given */
+ 	struct re_registers reregs;
+ 	unsigned int saveflags;
+ 	NODE *tmp;
+ 	NODE **lhs;
+ 	char *lastbuf;
+ 	int need_to_free = 0;
+ 
+ 	if (tree == NULL)
+ 		fatal("sub or gsub called with 0 arguments");
+ 	tmp = tree->lnode;
+ 	if (tmp->type == Node_regex) {
+ 		rp = tmp->rereg;
+ 		if (! strict && ((IGNORECASE_node->var_value->numbr != 0)
+ 		    ^ (tmp->re_case != 0))) {
+ 			/* recompile since case sensitivity differs */
+ 			rp = tmp->rereg =
+ 				mk_re_parse(tmp->re_text,
+ 				(IGNORECASE_node->var_value->numbr != 0));
+ 			tmp->re_case = (IGNORECASE_node->var_value->numbr != 0);
+ 		}
+ 	} else {
+ 		need_to_free = 1;
+ 		rp = make_regexp(force_string(tree_eval(tmp)),
+ 				(IGNORECASE_node->var_value->numbr != 0));
+ 		if (rp == NULL)
+ 			cant_happen();
+ 	}
+ 	tree = tree->rnode;
+ 	if (tree == NULL)
+ 		fatal("sub or gsub called with only 1 argument");
+ 	s = force_string(tree_eval(tree->lnode));
+ 	tree = tree->rnode;
+ 	deref = 0;
+ 	field_num = -1;
+ 	if (tree == NULL) {
+ 		t = node0_valid ? fields_arr[0] : *get_field(0, 0);
+ 		lhs = &fields_arr[0];
+ 		field_num = 0;
+ 		deref = t;
+ 	} else {
+ 		t = tree->lnode;
+ 		lhs = get_lhs(t, 1);
+ 		t = force_string(tree_eval(t));
+ 	}
+ 	/*
+ 	 * create a private copy of the string
+ 	 */
+ 	if (t->stref > 1 || (t->flags & PERM)) {
+ 		saveflags = t->flags;
+ 		t->flags &= ~MALLOC;
+ 		tmp = dupnode(t);
+ 		t->flags = saveflags;
+ 		do_deref();
+ 		t = tmp;
+ 		if (lhs)
+ 			*lhs = tmp;
+ 	}
+ 	lastbuf = t->stptr;
+ 	do {
+ 		if (re_search(rp, t->stptr, t->stlen, search_start,
+ 		    t->stlen-search_start, &reregs) == -1
+ 		    || reregs.start[0] == reregs.end[0])
+ 			break;
+ 		matches++;
+ 
+ 		/*
+ 		 * first, make a pass through the sub. pattern, to calculate
+ 		 * the length of the string after substitution 
+ 		 */
+ 		match_length = reregs.end[0] - reregs.start[0];
+ 		len = t->stlen - match_length;
+ 		for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
+ 			if (*scan == '&')
+ 				len += match_length;
+ 			else if (*scan == '\\' && *(scan+1) == '&') {
+ 				scan++;
+ 				len++;
+ 			} else
+ 				len++;
+ 		emalloc(buf, char *, len + 1, "do_sub");
+ 		bp = buf;
+ 
+ 		/*
+ 		 * now, create the result, copying in parts of the original
+ 		 * string 
+ 		 */
+ 		for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
+ 			*bp++ = *scan;
+ 		for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
+ 			if (*scan == '&')
+ 				for (cp = t->stptr + reregs.start[0];
+ 				     cp < t->stptr + reregs.end[0]; cp++)
+ 					*bp++ = *cp;
+ 			else if (*scan == '\\' && *(scan+1) == '&') {
+ 				scan++;
+ 				*bp++ = *scan;
+ 			} else
+ 				*bp++ = *scan;
+ 		search_start = bp - buf;
+ 		for (scan = t->stptr + reregs.end[0];
+ 		     scan < t->stptr + t->stlen; scan++)
+ 			*bp++ = *scan;
+ 		*bp = '\0';
+ 		free(lastbuf);
+ 		t->stptr = buf;
+ 		lastbuf = buf;
+ 		t->stlen = len;
+ 	} while (global && search_start < t->stlen);
+ 
+ 	free_temp(s);
+ 	if (need_to_free) {
+ 		free(rp->buffer);
+ 		free(rp->fastmap);
+ 		free((char *) rp);
+ 	}
+ 	if (matches > 0) {
+ 		if (field_num == 0)
+ 			set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
+ 		t->flags &= ~(NUM|NUMERIC);
+ 	}
+ 	field_num = -1;
+ 	return tmp_number((AWKNUM) matches);
+ }
+ 
+ NODE *
+ do_gsub(tree)
+ NODE *tree;
+ {
+ 	return sub_common(tree, 1);
+ }
+ 
+ NODE *
+ do_sub(tree)
+ NODE *tree;
+ {
+ 	return sub_common(tree, 0);
+ }
+ 


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/debug.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/debug.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/debug.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,561 ----
+ /*
+  * debug.c -- Various debugging routines 
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ #ifdef DEBUG
+ 
+ extern NODE **fields_arr;
+ 
+ 
+ /* This is all debugging stuff.  Ignore it and maybe it'll go away. */
+ 
+ /*
+  * Some of it could be turned into a really cute trace command, if anyone
+  * wants to.  
+  */
+ char *nnames[] = {
+ 	"illegal", "times", "quotient", "mod", "plus",
+ 	"minus", "cond_pair", "subscript", "concat", "exp",
+ 	/* 10 */
+ 	"preincrement", "predecrement", "postincrement", "postdecrement",
+ 	"unary_minus",
+ 	"field_spec", "assign", "assign_times", "assign_quotient", "assign_mod",
+ 	/* 20 */
+ 	"assign_plus", "assign_minus", "assign_exp", "and", "or",
+ 	"equal", "notequal", "less", "greater", "leq",
+ 	/* 30 */
+ 	"geq", "match", "nomatch", "not", "rule_list",
+ 	"rule_node", "statement_list", "if_branches", "expression_list",
+ 	"param_list",
+ 	/* 40 */
+ 	"K_if", "K_while", "K_for", "K_arrayfor", "K_break",
+ 	"K_continue", "K_print", "K_printf", "K_next", "K_exit",
+ 	/* 50 */
+ 	"K_do", "K_return", "K_delete", "K_getline", "K_function",
+ 	"redirect_output", "redirect_append", "redirect_pipe",
+ 	"redirect_pipein", "redirect_input",
+ 	/* 60 */
+ 	"var", "var_array", "val", "builtin", "line_range",
+ 	"in_array", "func", "func_call", "cond_exp", "regex",
+ 	/* 70 */
+ 	"hashnode", "ahash"
+ };
+ 
+ ptree(n)
+ NODE *n;
+ {
+ 	print_parse_tree(n);
+ }
+ 
+ pt()
+ {
+ 	long x;
+ 
+ 	(void) scanf("%x", &x);
+ 	printf("0x%x\n", x);
+ 	print_parse_tree((NODE *) x);
+ 	fflush(stdout);
+ }
+ 
+ static depth = 0;
+ 
+ print_parse_tree(ptr)
+ NODE *ptr;
+ {
+ 	if (!ptr) {
+ 		printf("NULL\n");
+ 		return;
+ 	}
+ 	if ((int) (ptr->type) < 0 || (int) (ptr->type) > sizeof(nnames) / sizeof(nnames[0])) {
+ 		printf("(0x%x Type %d??)\n", ptr, ptr->type);
+ 		return;
+ 	}
+ 	printf("(%d)%*s", depth, depth, "");
+ 	switch ((int) ptr->type) {
+ 	case (int) Node_val:
+ 		printf("(0x%x Value ", ptr);
+ 		if (ptr->flags&STR)
+ 			printf("str: \"%.*s\" ", ptr->stlen, ptr->stptr);
+ 		if (ptr->flags&NUM)
+ 			printf("num: %g", ptr->numbr);
+ 		printf(")\n");
+ 		return;
+ 	case (int) Node_var_array:
+ 		{
+ 		struct search *l;
+ 
+ 		printf("(0x%x Array)\n", ptr);
+ 		for (l = assoc_scan(ptr); l; l = assoc_next(l)) {
+ 			printf("\tindex: ");
+ 			print_parse_tree(l->retval);
+ 			printf("\tvalue: ");
+ 			print_parse_tree(*assoc_lookup(ptr, l->retval));
+ 			printf("\n");
+ 		}
+ 		return;
+ 		}
+ 	case Node_param_list:
+ 		printf("(0x%x Local variable %s)\n", ptr, ptr->param);
+ 		if (ptr->rnode)
+ 			print_parse_tree(ptr->rnode);
+ 		return;
+ 	case Node_regex:
+ 		printf("(0x%x Regular expression %s\n", ptr, ptr->re_text);
+ 		return;
+ 	}
+ 	if (ptr->lnode)
+ 		printf("0x%x = left<--", ptr->lnode);
+ 	printf("(0x%x %s.%d)", ptr, nnames[(int) (ptr->type)], ptr->type);
+ 	if (ptr->rnode)
+ 		printf("-->right = 0x%x", ptr->rnode);
+ 	printf("\n");
+ 	depth++;
+ 	if (ptr->lnode)
+ 		print_parse_tree(ptr->lnode);
+ 	switch ((int) ptr->type) {
+ 	case (int) Node_line_range:
+ 	case (int) Node_match:
+ 	case (int) Node_nomatch:
+ 		break;
+ 	case (int) Node_builtin:
+ 		printf("Builtin: %d\n", ptr->proc);
+ 		break;
+ 	case (int) Node_K_for:
+ 	case (int) Node_K_arrayfor:
+ 		printf("(%s:)\n", nnames[(int) (ptr->type)]);
+ 		print_parse_tree(ptr->forloop->init);
+ 		printf("looping:\n");
+ 		print_parse_tree(ptr->forloop->cond);
+ 		printf("doing:\n");
+ 		print_parse_tree(ptr->forloop->incr);
+ 		break;
+ 	default:
+ 		if (ptr->rnode)
+ 			print_parse_tree(ptr->rnode);
+ 		break;
+ 	}
+ 	--depth;
+ }
+ 
+ 
+ /*
+  * print out all the variables in the world 
+  */
+ 
+ dump_vars()
+ {
+ 	register int n;
+ 	register NODE *buc;
+ 
+ #ifdef notdef
+ 	printf("Fields:");
+ 	dump_fields();
+ #endif
+ 	printf("Vars:\n");
+ 	for (n = 0; n < HASHSIZE; n++) {
+ 		for (buc = variables[n]; buc; buc = buc->hnext) {
+ 			printf("'%.*s': ", buc->hlength, buc->hname);
+ 			print_parse_tree(buc->hvalue);
+ 		}
+ 	}
+ 	printf("End\n");
+ }
+ 
+ #ifdef notdef
+ dump_fields()
+ {
+ 	register NODE **p;
+ 	register int n;
+ 
+ 	printf("%d fields\n", f_arr_siz);
+ 	for (n = 0, p = &fields_arr[0]; n < f_arr_siz; n++, p++) {
+ 		printf("$%d is '", n);
+ 		print_simple(*p, stdout);
+ 		printf("'\n");
+ 	}
+ }
+ #endif
+ 
+ /* VARARGS1 */
+ print_debug(str, n)
+ char *str;
+ {
+ 	extern int debugging;
+ 
+ 	if (debugging)
+ 		printf("%s:0x%x\n", str, n);
+ }
+ 
+ int indent = 0;
+ 
+ print_a_node(ptr)
+ NODE *ptr;
+ {
+ 	NODE *p1;
+ 	char *str, *str2;
+ 	int n;
+ 	NODE *buc;
+ 
+ 	if (!ptr)
+ 		return;		/* don't print null ptrs */
+ 	switch (ptr->type) {
+ 	case Node_val:
+ 		if (ptr->flags&NUM)
+ 			printf("%g", ptr->numbr);
+ 		else
+ 			printf("\"%.*s\"", ptr->stlen, ptr->stptr);
+ 		return;
+ 	case Node_times:
+ 		str = "*";
+ 		goto pr_twoop;
+ 	case Node_quotient:
+ 		str = "/";
+ 		goto pr_twoop;
+ 	case Node_mod:
+ 		str = "%";
+ 		goto pr_twoop;
+ 	case Node_plus:
+ 		str = "+";
+ 		goto pr_twoop;
+ 	case Node_minus:
+ 		str = "-";
+ 		goto pr_twoop;
+ 	case Node_exp:
+ 		str = "^";
+ 		goto pr_twoop;
+ 	case Node_concat:
+ 		str = " ";
+ 		goto pr_twoop;
+ 	case Node_assign:
+ 		str = "=";
+ 		goto pr_twoop;
+ 	case Node_assign_times:
+ 		str = "*=";
+ 		goto pr_twoop;
+ 	case Node_assign_quotient:
+ 		str = "/=";
+ 		goto pr_twoop;
+ 	case Node_assign_mod:
+ 		str = "%=";
+ 		goto pr_twoop;
+ 	case Node_assign_plus:
+ 		str = "+=";
+ 		goto pr_twoop;
+ 	case Node_assign_minus:
+ 		str = "-=";
+ 		goto pr_twoop;
+ 	case Node_assign_exp:
+ 		str = "^=";
+ 		goto pr_twoop;
+ 	case Node_and:
+ 		str = "&&";
+ 		goto pr_twoop;
+ 	case Node_or:
+ 		str = "||";
+ 		goto pr_twoop;
+ 	case Node_equal:
+ 		str = "==";
+ 		goto pr_twoop;
+ 	case Node_notequal:
+ 		str = "!=";
+ 		goto pr_twoop;
+ 	case Node_less:
+ 		str = "<";
+ 		goto pr_twoop;
+ 	case Node_greater:
+ 		str = ">";
+ 		goto pr_twoop;
+ 	case Node_leq:
+ 		str = "<=";
+ 		goto pr_twoop;
+ 	case Node_geq:
+ 		str = ">=";
+ 		goto pr_twoop;
+ 
+ pr_twoop:
+ 		print_a_node(ptr->lnode);
+ 		printf("%s", str);
+ 		print_a_node(ptr->rnode);
+ 		return;
+ 
+ 	case Node_not:
+ 		str = "!";
+ 		str2 = "";
+ 		goto pr_oneop;
+ 	case Node_field_spec:
+ 		str = "$(";
+ 		str2 = ")";
+ 		goto pr_oneop;
+ 	case Node_postincrement:
+ 		str = "";
+ 		str2 = "++";
+ 		goto pr_oneop;
+ 	case Node_postdecrement:
+ 		str = "";
+ 		str2 = "--";
+ 		goto pr_oneop;
+ 	case Node_preincrement:
+ 		str = "++";
+ 		str2 = "";
+ 		goto pr_oneop;
+ 	case Node_predecrement:
+ 		str = "--";
+ 		str2 = "";
+ 		goto pr_oneop;
+ pr_oneop:
+ 		printf(str);
+ 		print_a_node(ptr->subnode);
+ 		printf(str2);
+ 		return;
+ 
+ 	case Node_expression_list:
+ 		print_a_node(ptr->lnode);
+ 		if (ptr->rnode) {
+ 			printf(",");
+ 			print_a_node(ptr->rnode);
+ 		}
+ 		return;
+ 
+ 	case Node_var:
+ 		for (n = 0; n < HASHSIZE; n++) {
+ 			for (buc = variables[n]; buc; buc = buc->hnext) {
+ 				if (buc->hvalue == ptr) {
+ 					printf("%.*s", buc->hlength, buc->hname);
+ 					n = HASHSIZE;
+ 					break;
+ 				}
+ 			}
+ 		}
+ 		return;
+ 	case Node_subscript:
+ 		print_a_node(ptr->lnode);
+ 		printf("[");
+ 		print_a_node(ptr->rnode);
+ 		printf("]");
+ 		return;
+ 	case Node_builtin:
+ 		printf("some_builtin(");
+ 		print_a_node(ptr->subnode);
+ 		printf(")");
+ 		return;
+ 
+ 	case Node_statement_list:
+ 		printf("{\n");
+ 		indent++;
+ 		for (n = indent; n; --n)
+ 			printf("  ");
+ 		while (ptr) {
+ 			print_maybe_semi(ptr->lnode);
+ 			if (ptr->rnode)
+ 				for (n = indent; n; --n)
+ 					printf("  ");
+ 			ptr = ptr->rnode;
+ 		}
+ 		--indent;
+ 		for (n = indent; n; --n)
+ 			printf("  ");
+ 		printf("}\n");
+ 		for (n = indent; n; --n)
+ 			printf("  ");
+ 		return;
+ 
+ 	case Node_K_if:
+ 		printf("if(");
+ 		print_a_node(ptr->lnode);
+ 		printf(") ");
+ 		ptr = ptr->rnode;
+ 		if (ptr->lnode->type == Node_statement_list) {
+ 			printf("{\n");
+ 			indent++;
+ 			for (p1 = ptr->lnode; p1; p1 = p1->rnode) {
+ 				for (n = indent; n; --n)
+ 					printf("  ");
+ 				print_maybe_semi(p1->lnode);
+ 			}
+ 			--indent;
+ 			for (n = indent; n; --n)
+ 				printf("  ");
+ 			if (ptr->rnode) {
+ 				printf("} else ");
+ 			} else {
+ 				printf("}\n");
+ 				return;
+ 			}
+ 		} else {
+ 			print_maybe_semi(ptr->lnode);
+ 			if (ptr->rnode) {
+ 				for (n = indent; n; --n)
+ 					printf("  ");
+ 				printf("else ");
+ 			} else
+ 				return;
+ 		}
+ 		if (!ptr->rnode)
+ 			return;
+ 		deal_with_curls(ptr->rnode);
+ 		return;
+ 
+ 	case Node_K_while:
+ 		printf("while(");
+ 		print_a_node(ptr->lnode);
+ 		printf(") ");
+ 		deal_with_curls(ptr->rnode);
+ 		return;
+ 
+ 	case Node_K_do:
+ 		printf("do ");
+ 		deal_with_curls(ptr->rnode);
+ 		printf("while(");
+ 		print_a_node(ptr->lnode);
+ 		printf(") ");
+ 		return;
+ 
+ 	case Node_K_for:
+ 		printf("for(");
+ 		print_a_node(ptr->forloop->init);
+ 		printf(";");
+ 		print_a_node(ptr->forloop->cond);
+ 		printf(";");
+ 		print_a_node(ptr->forloop->incr);
+ 		printf(") ");
+ 		deal_with_curls(ptr->forsub);
+ 		return;
+ 	case Node_K_arrayfor:
+ 		printf("for(");
+ 		print_a_node(ptr->forloop->init);
+ 		printf(" in ");
+ 		print_a_node(ptr->forloop->incr);
+ 		printf(") ");
+ 		deal_with_curls(ptr->forsub);
+ 		return;
+ 
+ 	case Node_K_printf:
+ 		printf("printf(");
+ 		print_a_node(ptr->lnode);
+ 		printf(")");
+ 		return;
+ 	case Node_K_print:
+ 		printf("print(");
+ 		print_a_node(ptr->lnode);
+ 		printf(")");
+ 		return;
+ 	case Node_K_next:
+ 		printf("next");
+ 		return;
+ 	case Node_K_break:
+ 		printf("break");
+ 		return;
+ 	case Node_K_delete:
+ 		printf("delete ");
+ 		print_a_node(ptr->lnode);
+ 		return;
+ 	case Node_func:
+ 		printf("function %s (", ptr->lnode->param);
+ 		if (ptr->lnode->rnode)
+ 			print_a_node(ptr->lnode->rnode);
+ 		printf(")\n");
+ 		print_a_node(ptr->rnode);
+ 		return;
+ 	case Node_param_list:
+ 		printf("%s", ptr->param);
+ 		if (ptr->rnode) {
+ 			printf(", ");
+ 			print_a_node(ptr->rnode);
+ 		}
+ 		return;
+ 	default:
+ 		print_parse_tree(ptr);
+ 		return;
+ 	}
+ }
+ 
+ print_maybe_semi(ptr)
+ NODE *ptr;
+ {
+ 	print_a_node(ptr);
+ 	switch (ptr->type) {
+ 	case Node_K_if:
+ 	case Node_K_for:
+ 	case Node_K_arrayfor:
+ 	case Node_statement_list:
+ 		break;
+ 	default:
+ 		printf(";\n");
+ 		break;
+ 	}
+ }
+ 
+ deal_with_curls(ptr)
+ NODE *ptr;
+ {
+ 	int n;
+ 
+ 	if (ptr->type == Node_statement_list) {
+ 		printf("{\n");
+ 		indent++;
+ 		while (ptr) {
+ 			for (n = indent; n; --n)
+ 				printf("  ");
+ 			print_maybe_semi(ptr->lnode);
+ 			ptr = ptr->rnode;
+ 		}
+ 		--indent;
+ 		for (n = indent; n; --n)
+ 			printf("  ");
+ 		printf("}\n");
+ 	} else {
+ 		print_maybe_semi(ptr);
+ 	}
+ }
+ 
+ NODE *
+ do_prvars()
+ {
+ 	dump_vars();
+ 	return Nnull_string;
+ }
+ 
+ NODE *
+ do_bp()
+ {
+ 	return Nnull_string;
+ }
+ 
+ #endif
+ 
+ #ifdef MEMDEBUG
+ 
+ #undef free
+ extern void free();
+ 
+ void
+ do_free(s)
+ char *s;
+ {
+ 	free(s);
+ }
+ 
+ #endif


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/eval.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/eval.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/eval.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,1139 ----
+ /*
+  * eval.c - gawk parse tree interpreter 
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ extern void do_print();
+ extern void do_printf();
+ extern NODE *do_match();
+ extern NODE *do_sub();
+ extern NODE *do_getline();
+ extern NODE *concat_exp();
+ extern int in_array();
+ extern void do_delete();
+ extern double pow();
+ 
+ static int eval_condition();
+ static NODE *op_assign();
+ static NODE *func_call();
+ static NODE *match_op();
+ 
+ NODE *_t;		/* used as a temporary in macros */
+ #ifdef MSDOS
+ double _msc51bug;	/* to get around a bug in MSC 5.1 */
+ #endif
+ NODE *ret_node;
+ 
+ /* More of that debugging stuff */
+ #ifdef	DEBUG
+ #define DBG_P(X) print_debug X
+ #else
+ #define DBG_P(X)
+ #endif
+ 
+ /* Macros and variables to save and restore function and loop bindings */
+ /*
+  * the val variable allows return/continue/break-out-of-context to be
+  * caught and diagnosed
+  */
+ #define PUSH_BINDING(stack, x, val) (memcpy ((char *)(stack), (char *)(x), sizeof (jmp_buf)), val++)
+ #define RESTORE_BINDING(stack, x, val) (memcpy ((char *)(x), (char *)(stack), sizeof (jmp_buf)), val--)
+ 
+ static jmp_buf loop_tag;	/* always the current binding */
+ static int loop_tag_valid = 0;	/* nonzero when loop_tag valid */
+ static int func_tag_valid = 0;
+ static jmp_buf func_tag;
+ extern int exiting, exit_val;
+ 
+ /*
+  * This table is used by the regexp routines to do case independant
+  * matching. Basically, every ascii character maps to itself, except
+  * uppercase letters map to lower case ones. This table has 256
+  * entries, which may be overkill. Note also that if the system this
+  * is compiled on doesn't use 7-bit ascii, casetable[] should not be
+  * defined to the linker, so gawk should not load.
+  *
+  * Do NOT make this array static, it is used in several spots, not
+  * just in this file.
+  */
+ #if 'a' == 97	/* it's ascii */
+ char casetable[] = {
+ 	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ 	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ 	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ 	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ 	/* ' '     '!'     '"'     '#'     '$'     '%'     '&'     ''' */
+ 	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ 	/* '('     ')'     '*'     '+'     ','     '-'     '.'     '/' */
+ 	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ 	/* '0'     '1'     '2'     '3'     '4'     '5'     '6'     '7' */
+ 	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ 	/* '8'     '9'     ':'     ';'     '<'     '='     '>'     '?' */
+ 	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ 	/* '@'     'A'     'B'     'C'     'D'     'E'     'F'     'G' */
+ 	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ 	/* 'H'     'I'     'J'     'K'     'L'     'M'     'N'     'O' */
+ 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ 	/* 'P'     'Q'     'R'     'S'     'T'     'U'     'V'     'W' */
+ 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ 	/* 'X'     'Y'     'Z'     '['     '\'     ']'     '^'     '_' */
+ 	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ 	/* '`'     'a'     'b'     'c'     'd'     'e'     'f'     'g' */
+ 	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ 	/* 'h'     'i'     'j'     'k'     'l'     'm'     'n'     'o' */
+ 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ 	/* 'p'     'q'     'r'     's'     't'     'u'     'v'     'w' */
+ 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ 	/* 'x'     'y'     'z'     '{'     '|'     '}'     '~' */
+ 	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ 	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ 	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ 	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ 	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ 	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ 	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ 	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ 	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ 	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ 	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ 	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ 	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ 	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ 	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ 	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ 	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+ };
+ #else
+ #include "You lose. You will need a translation table for your character set."
+ #endif
+ 
+ /*
+  * Tree is a bunch of rules to run. Returns zero if it hit an exit()
+  * statement 
+  */
+ int
+ interpret(tree)
+ NODE *tree;
+ {
+ 	volatile jmp_buf loop_tag_stack; /* shallow binding stack for loop_tag */
+ 	static jmp_buf rule_tag;/* tag the rule currently being run, for NEXT
+ 				 * and EXIT statements.  It is static because
+ 				 * there are no nested rules */
+ 	register NODE *t = NULL;/* temporary */
+ 	volatile NODE **lhs;	/* lhs == Left Hand Side for assigns, etc */
+ 	volatile struct search *l;	/* For array_for */
+ 	volatile NODE *stable_tree;
+ 
+ 	if (tree == NULL)
+ 		return 1;
+ 	sourceline = tree->source_line;
+ 	source = tree->source_file;
+ 	switch (tree->type) {
+ 	case Node_rule_list:
+ 		for (t = tree; t != NULL; t = t->rnode) {
+ 			tree = t->lnode;
+ 		/* FALL THROUGH */
+ 	case Node_rule_node:
+ 			sourceline = tree->source_line;
+ 			source = tree->source_file;
+ 			switch (setjmp(rule_tag)) {
+ 			case 0:	/* normal non-jump */
+ 				/* test pattern, if any */
+ 				if (tree->lnode == NULL 
+ 				    || eval_condition(tree->lnode)) {
+ 					DBG_P(("Found a rule", tree->rnode));
+ 					if (tree->rnode == NULL) {
+ 						/*
+ 						 * special case: pattern with
+ 						 * no action is equivalent to
+ 						 * an action of {print}
+ 						 */
+ 						NODE printnode;
+ 
+ 						printnode.type = Node_K_print;
+ 						printnode.lnode = NULL;
+ 						printnode.rnode = NULL;
+ 						do_print(&printnode);
+ 					} else if (tree->rnode->type == Node_illegal) {
+ 						/*
+ 						 * An empty statement
+ 						 * (``{ }'') is different
+ 						 * from a missing statement.
+ 						 * A missing statement is
+ 						 * equal to ``{ print }'' as
+ 						 * above, but an empty
+ 						 * statement is as in C, do
+ 						 * nothing.
+ 						 */
+ 					} else
+ 						(void) interpret(tree->rnode);
+ 				}
+ 				break;
+ 			case TAG_CONTINUE:	/* NEXT statement */
+ 				return 1;
+ 			case TAG_BREAK:
+ 				return 0;
+ 			default:
+ 				cant_happen();
+ 			}
+ 			if (t == NULL)
+ 				break;
+ 		}
+ 		break;
+ 
+ 	case Node_statement_list:
+ 		for (t = tree; t != NULL; t = t->rnode) {
+ 			DBG_P(("Statements", t->lnode));
+ 			(void) interpret(t->lnode);
+ 		}
+ 		break;
+ 
+ 	case Node_K_if:
+ 		DBG_P(("IF", tree->lnode));
+ 		if (eval_condition(tree->lnode)) {
+ 			DBG_P(("True", tree->rnode->lnode));
+ 			(void) interpret(tree->rnode->lnode);
+ 		} else {
+ 			DBG_P(("False", tree->rnode->rnode));
+ 			(void) interpret(tree->rnode->rnode);
+ 		}
+ 		break;
+ 
+ 	case Node_K_while:
+ 		PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 
+ 		DBG_P(("WHILE", tree->lnode));
+ 		stable_tree = tree;
+ 		while (eval_condition(stable_tree->lnode)) {
+ 			switch (setjmp(loop_tag)) {
+ 			case 0:	/* normal non-jump */
+ 				DBG_P(("DO", stable_tree->rnode));
+ 				(void) interpret(stable_tree->rnode);
+ 				break;
+ 			case TAG_CONTINUE:	/* continue statement */
+ 				break;
+ 			case TAG_BREAK:	/* break statement */
+ 				RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 				return 1;
+ 			default:
+ 				cant_happen();
+ 			}
+ 		}
+ 		RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		break;
+ 
+ 	case Node_K_do:
+ 		PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		stable_tree = tree;
+ 		do {
+ 			switch (setjmp(loop_tag)) {
+ 			case 0:	/* normal non-jump */
+ 				DBG_P(("DO", stable_tree->rnode));
+ 				(void) interpret(stable_tree->rnode);
+ 				break;
+ 			case TAG_CONTINUE:	/* continue statement */
+ 				break;
+ 			case TAG_BREAK:	/* break statement */
+ 				RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 				return 1;
+ 			default:
+ 				cant_happen();
+ 			}
+ 			DBG_P(("WHILE", stable_tree->lnode));
+ 		} while (eval_condition(stable_tree->lnode));
+ 		RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		break;
+ 
+ 	case Node_K_for:
+ 		PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		DBG_P(("FOR", tree->forloop->init));
+ 		(void) interpret(tree->forloop->init);
+ 		DBG_P(("FOR.WHILE", tree->forloop->cond));
+ 		stable_tree = tree;
+ 		while (eval_condition(stable_tree->forloop->cond)) {
+ 			switch (setjmp(loop_tag)) {
+ 			case 0:	/* normal non-jump */
+ 				DBG_P(("FOR.DO", stable_tree->lnode));
+ 				(void) interpret(stable_tree->lnode);
+ 				/* fall through */
+ 			case TAG_CONTINUE:	/* continue statement */
+ 				DBG_P(("FOR.INCR", stable_tree->forloop->incr));
+ 				(void) interpret(stable_tree->forloop->incr);
+ 				break;
+ 			case TAG_BREAK:	/* break statement */
+ 				RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 				return 1;
+ 			default:
+ 				cant_happen();
+ 			}
+ 		}
+ 		RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		break;
+ 
+ 	case Node_K_arrayfor:
+ #define hakvar forloop->init
+ #define arrvar forloop->incr
+ 		PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		DBG_P(("AFOR.VAR", tree->hakvar));
+ 		lhs = (volatile NODE **) get_lhs(tree->hakvar, 1);
+ 		t = tree->arrvar;
+ 		if (t->type == Node_param_list)
+ 			t = stack_ptr[t->param_cnt];
+ 		stable_tree = tree;
+ 		for (l = assoc_scan(t); l; l = assoc_next((struct search *)l)) {
+ 			deref = *((NODE **) lhs);
+ 			do_deref();
+ 			*lhs = dupnode(l->retval);
+ 			if (field_num == 0)
+ 				set_record(fields_arr[0]->stptr,
+ 				    fields_arr[0]->stlen);
+ 			DBG_P(("AFOR.NEXTIS", *lhs));
+ 			switch (setjmp(loop_tag)) {
+ 			case 0:
+ 				DBG_P(("AFOR.DO", stable_tree->lnode));
+ 				(void) interpret(stable_tree->lnode);
+ 			case TAG_CONTINUE:
+ 				break;
+ 
+ 			case TAG_BREAK:
+ 				RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 				field_num = -1;
+ 				return 1;
+ 			default:
+ 				cant_happen();
+ 			}
+ 		}
+ 		field_num = -1;
+ 		RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
+ 		break;
+ 
+ 	case Node_K_break:
+ 		DBG_P(("BREAK", NULL));
+ 		if (loop_tag_valid == 0)
+ 			fatal("unexpected break");
+ 		longjmp(loop_tag, TAG_BREAK);
+ 		break;
+ 
+ 	case Node_K_continue:
+ 		DBG_P(("CONTINUE", NULL));
+ 		if (loop_tag_valid == 0)
+ 			fatal("unexpected continue");
+ 		longjmp(loop_tag, TAG_CONTINUE);
+ 		break;
+ 
+ 	case Node_K_print:
+ 		DBG_P(("PRINT", tree));
+ 		do_print(tree);
+ 		break;
+ 
+ 	case Node_K_printf:
+ 		DBG_P(("PRINTF", tree));
+ 		do_printf(tree);
+ 		break;
+ 
+ 	case Node_K_next:
+ 		DBG_P(("NEXT", NULL));
+ 		longjmp(rule_tag, TAG_CONTINUE);
+ 		break;
+ 
+ 	case Node_K_exit:
+ 		/*
+ 		 * In A,K,&W, p. 49, it says that an exit statement "...
+ 		 * causes the program to behave as if the end of input had
+ 		 * occurred; no more input is read, and the END actions, if
+ 		 * any are executed." This implies that the rest of the rules
+ 		 * are not done. So we immediately break out of the main loop.
+ 		 */
+ 		DBG_P(("EXIT", NULL));
+ 		exiting = 1;
+ 		if (tree) {
+ 			t = tree_eval(tree->lnode);
+ 			exit_val = (int) force_number(t);
+ 		}
+ 		free_temp(t);
+ 		longjmp(rule_tag, TAG_BREAK);
+ 		break;
+ 
+ 	case Node_K_return:
+ 		DBG_P(("RETURN", NULL));
+ 		t = tree_eval(tree->lnode);
+ 		ret_node = dupnode(t);
+ 		free_temp(t);
+ 		longjmp(func_tag, TAG_RETURN);
+ 		break;
+ 
+ 	default:
+ 		/*
+ 		 * Appears to be an expression statement.  Throw away the
+ 		 * value. 
+ 		 */
+ 		DBG_P(("E", NULL));
+ 		t = tree_eval(tree);
+ 		free_temp(t);
+ 		break;
+ 	}
+ 	return 1;
+ }
+ 
+ /* evaluate a subtree, allocating strings on a temporary stack. */
+ 
+ NODE *
+ r_tree_eval(tree)
+ NODE *tree;
+ {
+ 	register NODE *r, *t1, *t2;	/* return value & temporary subtrees */
+ 	int i;
+ 	register NODE **lhs;
+ 	int di;
+ 	AWKNUM x, x2;
+ 	long lx;
+ 	extern NODE **fields_arr;
+ 
+ 	source = tree->source_file;
+ 	sourceline = tree->source_line;
+ 	switch (tree->type) {
+ 	case Node_and:
+ 		DBG_P(("AND", tree));
+ 		return tmp_number((AWKNUM) (eval_condition(tree->lnode)
+ 					    && eval_condition(tree->rnode)));
+ 
+ 	case Node_or:
+ 		DBG_P(("OR", tree));
+ 		return tmp_number((AWKNUM) (eval_condition(tree->lnode)
+ 					    || eval_condition(tree->rnode)));
+ 
+ 	case Node_not:
+ 		DBG_P(("NOT", tree));
+ 		return tmp_number((AWKNUM) ! eval_condition(tree->lnode));
+ 
+ 		/* Builtins */
+ 	case Node_builtin:
+ 		DBG_P(("builtin", tree));
+ 		return ((*tree->proc) (tree->subnode));
+ 
+ 	case Node_K_getline:
+ 		DBG_P(("GETLINE", tree));
+ 		return (do_getline(tree));
+ 
+ 	case Node_in_array:
+ 		DBG_P(("IN_ARRAY", tree));
+ 		return tmp_number((AWKNUM) in_array(tree->lnode, tree->rnode));
+ 
+ 	case Node_func_call:
+ 		DBG_P(("func_call", tree));
+ 		return func_call(tree->rnode, tree->lnode);
+ 
+ 	case Node_K_delete:
+ 		DBG_P(("DELETE", tree));
+ 		do_delete(tree->lnode, tree->rnode);
+ 		return Nnull_string;
+ 
+ 		/* unary operations */
+ 
+ 	case Node_var:
+ 	case Node_var_array:
+ 	case Node_param_list:
+ 	case Node_subscript:
+ 	case Node_field_spec:
+ 		DBG_P(("var_type ref", tree));
+ 		lhs = get_lhs(tree, 0);
+ 		field_num = -1;
+ 		deref = 0;
+ 		return *lhs;
+ 
+ 	case Node_unary_minus:
+ 		DBG_P(("UMINUS", tree));
+ 		t1 = tree_eval(tree->subnode);
+ 		x = -force_number(t1);
+ 		free_temp(t1);
+ 		return tmp_number(x);
+ 
+ 	case Node_cond_exp:
+ 		DBG_P(("?:", tree));
+ 		if (eval_condition(tree->lnode)) {
+ 			DBG_P(("True", tree->rnode->lnode));
+ 			return tree_eval(tree->rnode->lnode);
+ 		}
+ 		DBG_P(("False", tree->rnode->rnode));
+ 		return tree_eval(tree->rnode->rnode);
+ 
+ 	case Node_match:
+ 	case Node_nomatch:
+ 	case Node_regex:
+ 		DBG_P(("[no]match_op", tree));
+ 		return match_op(tree);
+ 
+ 	case Node_func:
+ 		fatal("function `%s' called with space between name and (,\n%s",
+ 			tree->lnode->param,
+ 			"or used in other expression context");
+ 
+ 	/* assignments */
+ 	case Node_assign:
+ 		DBG_P(("ASSIGN", tree));
+ 		r = tree_eval(tree->rnode);
+ 		lhs = get_lhs(tree->lnode, 1);
+ 		*lhs = dupnode(r);
+ 		free_temp(r);
+ 		do_deref();
+ 		if (field_num == 0)
+ 			set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
+ 		field_num = -1;
+ 		return *lhs;
+ 
+ 	/* other assignment types are easier because they are numeric */
+ 	case Node_preincrement:
+ 	case Node_predecrement:
+ 	case Node_postincrement:
+ 	case Node_postdecrement:
+ 	case Node_assign_exp:
+ 	case Node_assign_times:
+ 	case Node_assign_quotient:
+ 	case Node_assign_mod:
+ 	case Node_assign_plus:
+ 	case Node_assign_minus:
+ 		return op_assign(tree);
+ 	default:
+ 		break;	/* handled below */
+ 	}
+ 
+ 	/* evaluate subtrees in order to do binary operation, then keep going */
+ 	t1 = tree_eval(tree->lnode);
+ 	t2 = tree_eval(tree->rnode);
+ 
+ 	switch (tree->type) {
+ 	case Node_concat:
+ 		DBG_P(("CONCAT", tree));
+ 		t1 = force_string(t1);
+ 		t2 = force_string(t2);
+ 
+ 		r = newnode(Node_val);
+ 		r->flags |= (STR|TEMP);
+ 		r->stlen = t1->stlen + t2->stlen;
+ 		r->stref = 1;
+ 		emalloc(r->stptr, char *, r->stlen + 1, "tree_eval");
+ 		memcpy(r->stptr, t1->stptr, t1->stlen);
+ 		memcpy(r->stptr + t1->stlen, t2->stptr, t2->stlen + 1);
+ 		free_temp(t1);
+ 		free_temp(t2);
+ 		return r;
+ 
+ 	case Node_geq:
+ 	case Node_leq:
+ 	case Node_greater:
+ 	case Node_less:
+ 	case Node_notequal:
+ 	case Node_equal:
+ 		di = cmp_nodes(t1, t2);
+ 		free_temp(t1);
+ 		free_temp(t2);
+ 		switch (tree->type) {
+ 		case Node_equal:
+ 			DBG_P(("EQUAL", tree));
+ 			return tmp_number((AWKNUM) (di == 0));
+ 		case Node_notequal:
+ 			DBG_P(("NOT_EQUAL", tree));
+ 			return tmp_number((AWKNUM) (di != 0));
+ 		case Node_less:
+ 			DBG_P(("LESS_THAN", tree));
+ 			return tmp_number((AWKNUM) (di < 0));
+ 		case Node_greater:
+ 			DBG_P(("GREATER_THAN", tree));
+ 			return tmp_number((AWKNUM) (di > 0));
+ 		case Node_leq:
+ 			DBG_P(("LESS_THAN_EQUAL", tree));
+ 			return tmp_number((AWKNUM) (di <= 0));
+ 		case Node_geq:
+ 			DBG_P(("GREATER_THAN_EQUAL", tree));
+ 			return tmp_number((AWKNUM) (di >= 0));
+ 		default:
+ 			cant_happen();
+ 		}
+ 		break;
+ 	default:
+ 		break;	/* handled below */
+ 	}
+ 
+ 	(void) force_number(t1);
+ 	(void) force_number(t2);
+ 
+ 	switch (tree->type) {
+ 	case Node_exp:
+ 		DBG_P(("EXPONENT", tree));
+ 		if ((lx = t2->numbr) == t2->numbr) {	/* integer exponent */
+ 			if (lx == 0)
+ 				x = 1;
+ 			else if (lx == 1)
+ 				x = t1->numbr;
+ 			else {
+ 				/* doing it this way should be more precise */
+ 				for (x = x2 = t1->numbr; --lx; )
+ 					x *= x2;
+ 			}
+ 		} else
+ 			x = pow((double) t1->numbr, (double) t2->numbr);
+ 		free_temp(t1);
+ 		free_temp(t2);
+ 		return tmp_number(x);
+ 
+ 	case Node_times:
+ 		DBG_P(("MULT", tree));
+ 		x = t1->numbr * t2->numbr;
+ 		free_temp(t1);
+ 		free_temp(t2);
+ 		return tmp_number(x);
+ 
+ 	case Node_quotient:
+ 		DBG_P(("DIVIDE", tree));
+ 		x = t2->numbr;
+ 		free_temp(t2);
+ 		if (x == (AWKNUM) 0)
+ 			fatal("division by zero attempted");
+ 			/* NOTREACHED */
+ 		else {
+ 			x = t1->numbr / x;
+ 			free_temp(t1);
+ 			return tmp_number(x);
+ 		}
+ 
+ 	case Node_mod:
+ 		DBG_P(("MODULUS", tree));
+ 		x = t2->numbr;
+ 		free_temp(t2);
+ 		if (x == (AWKNUM) 0)
+ 			fatal("division by zero attempted in mod");
+ 			/* NOTREACHED */
+ 		lx = t1->numbr / x;	/* assignment to long truncates */
+ 		x2 = lx * x;
+ 		x = t1->numbr - x2;
+ 		free_temp(t1);
+ 		return tmp_number(x);
+ 
+ 	case Node_plus:
+ 		DBG_P(("PLUS", tree));
+ 		x = t1->numbr + t2->numbr;
+ 		free_temp(t1);
+ 		free_temp(t2);
+ 		return tmp_number(x);
+ 
+ 	case Node_minus:
+ 		DBG_P(("MINUS", tree));
+ 		x = t1->numbr - t2->numbr;
+ 		free_temp(t1);
+ 		free_temp(t2);
+ 		return tmp_number(x);
+ 
+ 	default:
+ 		fatal("illegal type (%d) in tree_eval", tree->type);
+ 	}
+ 	return 0;
+ }
+ 
+ /*
+  * This makes numeric operations slightly more efficient. Just change the
+  * value of a numeric node, if possible 
+  */
+ void
+ assign_number(ptr, value)
+ NODE **ptr;
+ AWKNUM value;
+ {
+ 	extern NODE *deref;
+ 	register NODE *n = *ptr;
+ 
+ #ifdef DEBUG
+ 	if (n->type != Node_val)
+ 		cant_happen();
+ #endif
+ 	if (n == Nnull_string) {
+ 		*ptr = make_number(value);
+ 		deref = 0;
+ 		return;
+ 	}
+ 	if (n->stref > 1) {
+ 		*ptr = make_number(value);
+ 		return;
+ 	}
+ 	if ((n->flags & STR) && (n->flags & (MALLOC|TEMP)))
+ 		free(n->stptr);
+ 	n->numbr = value;
+ 	n->flags |= (NUM|NUMERIC);
+ 	n->flags &= ~STR;
+ 	n->stref = 0;
+ 	deref = 0;
+ }
+ 
+ 
+ /* Is TREE true or false?  Returns 0==false, non-zero==true */
+ static int
+ eval_condition(tree)
+ NODE *tree;
+ {
+ 	register NODE *t1;
+ 	int ret;
+ 
+ 	if (tree == NULL)	/* Null trees are the easiest kinds */
+ 		return 1;
+ 	if (tree->type == Node_line_range) {
+ 		/*
+ 		 * Node_line_range is kind of like Node_match, EXCEPT: the
+ 		 * lnode field (more properly, the condpair field) is a node
+ 		 * of a Node_cond_pair; whether we evaluate the lnode of that
+ 		 * node or the rnode depends on the triggered word.  More
+ 		 * precisely:  if we are not yet triggered, we tree_eval the
+ 		 * lnode; if that returns true, we set the triggered word. 
+ 		 * If we are triggered (not ELSE IF, note), we tree_eval the
+ 		 * rnode, clear triggered if it succeeds, and perform our
+ 		 * action (regardless of success or failure).  We want to be
+ 		 * able to begin and end on a single input record, so this
+ 		 * isn't an ELSE IF, as noted above.
+ 		 */
+ 		if (!tree->triggered)
+ 			if (!eval_condition(tree->condpair->lnode))
+ 				return 0;
+ 			else
+ 				tree->triggered = 1;
+ 		/* Else we are triggered */
+ 		if (eval_condition(tree->condpair->rnode))
+ 			tree->triggered = 0;
+ 		return 1;
+ 	}
+ 
+ 	/*
+ 	 * Could just be J.random expression. in which case, null and 0 are
+ 	 * false, anything else is true 
+ 	 */
+ 
+ 	t1 = tree_eval(tree);
+ 	if (t1->flags & NUMERIC)
+ 		ret = t1->numbr != 0.0;
+ 	else
+ 		ret = t1->stlen != 0;
+ 	free_temp(t1);
+ 	return ret;
+ }
+ 
+ int
+ cmp_nodes(t1, t2)
+ NODE *t1, *t2;
+ {
+ 	AWKNUM d;
+ 	AWKNUM d1;
+ 	AWKNUM d2;
+ 	int ret;
+ 	int len1, len2;
+ 
+ 	if (t1 == t2)
+ 		return 0;
+ 	d1 = force_number(t1);
+ 	d2 = force_number(t2);
+ 	if ((t1->flags & NUMERIC) && (t2->flags & NUMERIC)) {
+ 		d = d1 - d2;
+ 		if (d == 0.0)	/* from profiling, this is most common */
+ 			return 0;
+ 		if (d > 0.0)
+ 			return 1;
+ 		return -1;
+ 	}
+ 	t1 = force_string(t1);
+ 	t2 = force_string(t2);
+ 	len1 = t1->stlen;
+ 	len2 = t2->stlen;
+ 	if (len1 == 0) {
+ 		if (len2 == 0)
+ 			return 0;
+ 		else
+ 			return -1;
+ 	} else if (len2 == 0)
+ 		return 1;
+ 	ret = memcmp(t1->stptr, t2->stptr, len1 <= len2 ? len1 : len2);
+ 	if (ret == 0 && len1 != len2)
+ 		return len1 < len2 ? -1: 1;
+ 	return ret;
+ }
+ 
+ static NODE *
+ op_assign(tree)
+ NODE *tree;
+ {
+ 	AWKNUM rval, lval;
+ 	NODE **lhs;
+ 	AWKNUM t1, t2;
+ 	long ltemp;
+ 	NODE *tmp;
+ 
+ 	lhs = get_lhs(tree->lnode, 1);
+ 	lval = force_number(*lhs);
+ 
+ 	switch(tree->type) {
+ 	case Node_preincrement:
+ 	case Node_predecrement:
+ 		DBG_P(("+-X", tree));
+ 		assign_number(lhs,
+ 		    lval + (tree->type == Node_preincrement ? 1.0 : -1.0));
+ 		do_deref();
+ 		if (field_num == 0)
+ 			set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
+ 		field_num = -1;
+ 		return *lhs;
+ 
+ 	case Node_postincrement:
+ 	case Node_postdecrement:
+ 		DBG_P(("X+-", tree));
+ 		assign_number(lhs,
+ 		    lval + (tree->type == Node_postincrement ? 1.0 : -1.0));
+ 		do_deref();
+ 		if (field_num == 0)
+ 			set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
+ 		field_num = -1;
+ 		return tmp_number(lval);
+ 	default:
+ 		break;	/* handled below */
+ 	}
+ 
+ 	tmp = tree_eval(tree->rnode);
+ 	rval = force_number(tmp);
+ 	free_temp(tmp);
+ 	switch(tree->type) {
+ 	case Node_assign_exp:
+ 		DBG_P(("ASSIGN_exp", tree));
+ 		if ((ltemp = rval) == rval) {	/* integer exponent */
+ 			if (ltemp == 0)
+ 				assign_number(lhs, (AWKNUM) 1);
+ 			else if (ltemp == 1)
+ 				assign_number(lhs, lval);
+ 			else {
+ 				/* doing it this way should be more precise */
+ 				for (t1 = t2 = lval; --ltemp; )
+ 					t1 *= t2;
+ 				assign_number(lhs, t1);
+ 			}
+ 		} else
+ 			assign_number(lhs, (AWKNUM) pow((double) lval, (double) rval));
+ 		break;
+ 
+ 	case Node_assign_times:
+ 		DBG_P(("ASSIGN_times", tree));
+ 		assign_number(lhs, lval * rval);
+ 		break;
+ 
+ 	case Node_assign_quotient:
+ 		DBG_P(("ASSIGN_quotient", tree));
+ 		if (rval == (AWKNUM) 0)
+ 			fatal("division by zero attempted in /=");
+ 		assign_number(lhs, lval / rval);
+ 		break;
+ 
+ 	case Node_assign_mod:
+ 		DBG_P(("ASSIGN_mod", tree));
+ 		if (rval == (AWKNUM) 0)
+ 			fatal("division by zero attempted in %=");
+ 		ltemp = lval / rval;	/* assignment to long truncates */
+ 		t1 = ltemp * rval;
+ 		t2 = lval - t1;
+ 		assign_number(lhs, t2);
+ 		break;
+ 
+ 	case Node_assign_plus:
+ 		DBG_P(("ASSIGN_plus", tree));
+ 		assign_number(lhs, lval + rval);
+ 		break;
+ 
+ 	case Node_assign_minus:
+ 		DBG_P(("ASSIGN_minus", tree));
+ 		assign_number(lhs, lval - rval);
+ 		break;
+ 	default:
+ 		cant_happen();
+ 	}
+ 	do_deref();
+ 	if (field_num == 0)
+ 		set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
+ 	field_num = -1;
+ 	return *lhs;
+ }
+ 
+ NODE **stack_ptr;
+ 
+ static NODE *
+ func_call(name, arg_list)
+ NODE *name;		/* name is a Node_val giving function name */
+ NODE *arg_list;		/* Node_expression_list of calling args. */
+ {
+ 	register NODE *arg, *argp, *r;
+ 	NODE *n, *f;
+ 	volatile jmp_buf func_tag_stack;
+ 	volatile jmp_buf loop_tag_stack;
+ 	volatile int save_loop_tag_valid = 0;
+ 	volatile NODE **save_stack, *save_ret_node;
+ 	NODE **local_stack, **sp;
+ 	int count;
+ 	extern NODE *ret_node;
+ 
+ 	/*
+ 	 * retrieve function definition node
+ 	 */
+ 	f = lookup(variables, name->stptr);
+ 	if (!f || f->type != Node_func)
+ 		fatal("function `%s' not defined", name->stptr);
+ #ifdef FUNC_TRACE
+ 	fprintf(stderr, "function %s called\n", name->stptr);
+ #endif
+ 	count = f->lnode->param_cnt;
+ 	emalloc(local_stack, NODE **, count * sizeof(NODE *), "func_call");
+ 	sp = local_stack;
+ 
+ 	/*
+ 	 * for each calling arg. add NODE * on stack
+ 	 */
+ 	for (argp = arg_list; count && argp != NULL; argp = argp->rnode) {
+ 		arg = argp->lnode;
+ 		r = newnode(Node_var);
+ 		/*
+ 		 * call by reference for arrays; see below also
+ 		 */
+ 		if (arg->type == Node_param_list)
+ 			arg = stack_ptr[arg->param_cnt];
+ 		if (arg->type == Node_var_array)
+ 			*r = *arg;
+ 		else {
+ 			n = tree_eval(arg);
+ 			r->lnode = dupnode(n);
+ 			r->rnode = (NODE *) NULL;
+ 			free_temp(n);
+   		}
+ 		*sp++ = r;
+ 		count--;
+ 	}
+ 	if (argp != NULL)	/* left over calling args. */
+ 		warning(
+ 		    "function `%s' called with more arguments than declared",
+ 		    name->stptr);
+ 	/*
+ 	 * add remaining params. on stack with null value
+ 	 */
+ 	while (count-- > 0) {
+ 		r = newnode(Node_var);
+ 		r->lnode = Nnull_string;
+ 		r->rnode = (NODE *) NULL;
+ 		*sp++ = r;
+ 	}
+ 
+ 	/*
+ 	 * Execute function body, saving context, as a return statement
+ 	 * will longjmp back here.
+ 	 *
+ 	 * Have to save and restore the loop_tag stuff so that a return
+ 	 * inside a loop in a function body doesn't scrog any loops going
+ 	 * on in the main program.  We save the necessary info in variables
+ 	 * local to this function so that function nesting works OK.
+ 	 * We also only bother to save the loop stuff if we're in a loop
+ 	 * when the function is called.
+ 	 */
+ 	if (loop_tag_valid) {
+ 		int junk = 0;
+ 
+ 		save_loop_tag_valid = (volatile int) loop_tag_valid;
+ 		PUSH_BINDING(loop_tag_stack, loop_tag, junk);
+ 		loop_tag_valid = 0;
+ 	}
+ 	save_stack = (volatile NODE **) stack_ptr;
+ 	stack_ptr = local_stack;
+ 	PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid);
+ 	save_ret_node = (volatile NODE *) ret_node;
+ 	ret_node = Nnull_string;	/* default return value */
+ 	if (setjmp(func_tag) == 0)
+ 		(void) interpret(f->rnode);
+ 
+ 	r = ret_node;
+ 	ret_node = (NODE *) save_ret_node;
+ 	RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid);
+ 	stack_ptr = (NODE **) save_stack;
+ 
+ 	/*
+ 	 * here, we pop each parameter and check whether
+ 	 * it was an array.  If so, and if the arg. passed in was
+ 	 * a simple variable, then the value should be copied back.
+ 	 * This achieves "call-by-reference" for arrays.
+ 	 */
+ 	sp = local_stack;
+ 	count = f->lnode->param_cnt;
+ 	for (argp = arg_list; count > 0 && argp != NULL; argp = argp->rnode) {
+ 		arg = argp->lnode;
+ 		n = *sp++;
+ 		if (arg->type == Node_var && n->type == Node_var_array) {
+ 			arg->var_array = n->var_array;
+ 			arg->type = Node_var_array;
+ 		}
+ 		deref = n->lnode;
+ 		do_deref();
+ 		freenode(n);
+ 		count--;
+ 	}
+ 	while (count-- > 0) {
+ 		n = *sp++;
+ 		deref = n->lnode;
+ 		do_deref();
+ 		freenode(n);
+ 	}
+ 	free((char *) local_stack);
+ 
+ 	/* Restore the loop_tag stuff if necessary. */
+ 	if (save_loop_tag_valid) {
+ 		int junk = 0;
+ 
+ 		loop_tag_valid = (int) save_loop_tag_valid;
+ 		RESTORE_BINDING(loop_tag_stack, loop_tag, junk);
+ 	}
+ 
+ 	if (!(r->flags & PERM))
+ 		r->flags |= TEMP;
+ 	return r;
+ }
+ 
+ /*
+  * This returns a POINTER to a node pointer. get_lhs(ptr) is the current
+  * value of the var, or where to store the var's new value 
+  */
+ 
+ NODE **
+ get_lhs(ptr, assign)
+ NODE *ptr;
+ int assign;		/* this is being called for the LHS of an assign. */
+ {
+ 	register NODE **aptr;
+ 	NODE *n;
+ 
+ #ifdef DEBUG
+ 	if (ptr == NULL)
+ 		cant_happen();
+ #endif
+ 	deref = NULL;
+ 	field_num = -1;
+ 	switch (ptr->type) {
+ 	case Node_var:
+ 	case Node_var_array:
+ 		if (ptr == NF_node && (int) NF_node->var_value->numbr == -1)
+ 			(void) get_field(HUGE-1, assign); /* parse record */
+ 		deref = ptr->var_value;
+ #ifdef DEBUG
+ 		if (deref->type != Node_val)
+ 			cant_happen();
+ 		if (deref->flags == 0)
+ 			cant_happen();
+ #endif
+ 		return &(ptr->var_value);
+ 
+ 	case Node_param_list:
+ 		n = stack_ptr[ptr->param_cnt];
+ 		deref = n->var_value;
+ #ifdef DEBUG
+ 		if (deref->type != Node_val)
+ 			cant_happen();
+ 		if (deref->flags == 0)
+ 			cant_happen();
+ #endif
+ 		return &(n->var_value);
+ 
+ 	case Node_field_spec:
+ 		n = tree_eval(ptr->lnode);
+ 		field_num = (int) force_number(n);
+ 		free_temp(n);
+ 		if (field_num < 0)
+ 			fatal("attempt to access field %d", field_num);
+ 		aptr = get_field(field_num, assign);
+ 		deref = *aptr;
+ 		return aptr;
+ 
+ 	case Node_subscript:
+ 		n = ptr->lnode;
+ 		if (n->type == Node_param_list)
+ 			n = stack_ptr[n->param_cnt];
+ 		aptr = assoc_lookup(n, concat_exp(ptr->rnode));
+ 		deref = *aptr;
+ #ifdef DEBUG
+ 		if (deref->type != Node_val)
+ 			cant_happen();
+ 		if (deref->flags == 0)
+ 			cant_happen();
+ #endif
+ 		return aptr;
+ 	case Node_func:
+ 		fatal ("`%s' is a function, assignment is not allowed",
+ 			ptr->lnode->param);
+ 	default:
+ 		cant_happen();
+ 	}
+ 	return 0;
+ }
+ 
+ static NODE *
+ match_op(tree)
+ NODE *tree;
+ {
+ 	NODE *t1;
+ 	struct re_pattern_buffer *rp;
+ 	int i;
+ 	int match = 1;
+ 
+ 	if (tree->type == Node_nomatch)
+ 		match = 0;
+ 	if (tree->type == Node_regex)
+ 		t1 = WHOLELINE;
+ 	else {
+ 		if (tree->lnode)
+ 			t1 = force_string(tree_eval(tree->lnode));
+ 		else
+ 			t1 = WHOLELINE;
+ 		tree = tree->rnode;
+ 	}
+ 	if (tree->type == Node_regex) {
+ 		rp = tree->rereg;
+ 		if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
+ 		    ^ (tree->re_case != 0))) {
+ 			/* recompile since case sensitivity differs */
+ 			rp = tree->rereg =
+ 			    mk_re_parse(tree->re_text,
+ 			    (IGNORECASE_node->var_value->numbr != 0));
+ 			tree->re_case =
+ 			    (IGNORECASE_node->var_value->numbr != 0);
+ 		}
+ 	} else {
+ 		rp = make_regexp(force_string(tree_eval(tree)),
+ 			(IGNORECASE_node->var_value->numbr != 0));
+ 		if (rp == NULL)
+ 			cant_happen();
+ 	}
+ 	i = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen,
+ 		(struct re_registers *) NULL);
+ 	i = (i == -1) ^ (match == 1);
+ 	free_temp(t1);
+ 	if (tree->type != Node_regex) {
+ 		free(rp->buffer);
+ 		free(rp->fastmap);
+ 		free((char *) rp);
+ 	}
+ 	return tmp_number((AWKNUM) i);
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/field.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/field.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/field.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,424 ----
+ /*
+  * field.c - routines for dealing with fields and record parsing
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ extern void assoc_clear();
+ extern int a_get_three();
+ extern int get_rs();
+ 
+ static char *get_fs();
+ static int re_split();
+ static int parse_fields();
+ static void set_element();
+ 
+ char *line_buf = NULL;	/* holds current input line */
+ 
+ static char *parse_extent;	/* marks where to restart parse of record */
+ static int parse_high_water=0;	/* field number that we have parsed so far */
+ static char f_empty[] = "";
+ static char *save_fs = " ";	/* save current value of FS when line is read,
+ 				 * to be used in deferred parsing
+ 				 */
+ 
+ 
+ NODE **fields_arr;		/* array of pointers to the field nodes */
+ NODE node0;			/* node for $0 which never gets free'd */
+ int node0_valid = 1;		/* $(>0) has not been changed yet */
+ 
+ void
+ init_fields()
+ {
+ 	emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
+ 	node0.type = Node_val;
+ 	node0.stref = 0;
+ 	node0.stptr = "";
+ 	node0.flags = (STR|PERM);	/* never free buf */
+ 	fields_arr[0] = &node0;
+ }
+ 
+ /*
+  * Danger!  Must only be called for fields we know have just been blanked, or
+  * fields we know don't exist yet.  
+  */
+ 
+ /*ARGSUSED*/
+ static void
+ set_field(num, str, len, dummy)
+ int num;
+ char *str;
+ int len;
+ NODE *dummy;	/* not used -- just to make interface same as set_element */
+ {
+ 	NODE *n;
+ 	int t;
+ 	static int nf_high_water = 0;
+ 
+ 	if (num > nf_high_water) {
+ 		erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
+ 		nf_high_water = num;
+ 	}
+ 	/* fill in fields that don't exist */
+ 	for (t = parse_high_water + 1; t < num; t++)
+ 		fields_arr[t] = Nnull_string;
+ 	n = make_string(str, len);
+ 	(void) force_number(n);
+ 	fields_arr[num] = n;
+ 	parse_high_water = num;
+ }
+ 
+ /* Someone assigned a value to $(something).  Fix up $0 to be right */
+ static void
+ rebuild_record()
+ {
+ 	register int tlen;
+ 	register NODE *tmp;
+ 	NODE *ofs;
+ 	char *ops;
+ 	register char *cops;
+ 	register NODE **ptr;
+ 	register int ofslen;
+ 
+ 	tlen = 0;
+ 	ofs = force_string(OFS_node->var_value);
+ 	ofslen = ofs->stlen;
+ 	ptr = &fields_arr[parse_high_water];
+ 	while (ptr > &fields_arr[0]) {
+ 		tmp = force_string(*ptr);
+ 		tlen += tmp->stlen;
+ 		ptr--;
+ 	}
+ 	tlen += (parse_high_water - 1) * ofslen;
+ 	emalloc(ops, char *, tlen + 1, "fix_fields");
+ 	cops = ops;
+ 	ops[0] = '\0';
+ 	for (ptr = &fields_arr[1]; ptr <= &fields_arr[parse_high_water]; ptr++) {
+ 		tmp = *ptr;
+ 		if (tmp->stlen == 1)
+ 			*cops++ = tmp->stptr[0];
+ 		else if (tmp->stlen != 0) {
+ 			memcpy(cops, tmp->stptr, tmp->stlen);
+ 			cops += tmp->stlen;
+ 		}
+ 		if (ptr != &fields_arr[parse_high_water]) {
+ 			if (ofslen == 1)
+ 				*cops++ = ofs->stptr[0];
+ 			else if (ofslen != 0) {
+ 				memcpy(cops, ofs->stptr, ofslen);
+ 				cops += ofslen;
+ 			}
+ 		}
+ 	}
+ 	tmp = make_string(ops, tlen);
+ 	free(ops);
+ 	deref = fields_arr[0];
+ 	do_deref();
+ 	fields_arr[0] = tmp;
+ }
+ 
+ /*
+  * setup $0, but defer parsing rest of line until reference is made to $(>0)
+  * or to NF.  At that point, parse only as much as necessary.
+  */
+ void
+ set_record(buf, cnt)
+ char *buf;
+ int cnt;
+ {
+ 	register int i;
+ 
+ 	assign_number(&NF_node->var_value, (AWKNUM)-1);
+ 	for (i = 1; i <= parse_high_water; i++) {
+ 		deref = fields_arr[i];
+ 		do_deref();
+ 	}
+ 	parse_high_water = 0;
+ 	node0_valid = 1;
+ 	if (buf == line_buf) {
+ 		deref = fields_arr[0];
+ 		do_deref();
+ 		save_fs = get_fs();
+ 		node0.type = Node_val;
+ 		node0.stptr = buf;
+ 		node0.stlen = cnt;
+ 		node0.stref = 1;
+ 		node0.flags = (STR|PERM);	/* never free buf */
+ 		fields_arr[0] = &node0;
+ 	}
+ }
+ 
+ NODE **
+ get_field(num, assign)
+ int num;
+ int assign;	/* this field is on the LHS of an assign */
+ {
+ 	int n;
+ 
+ 	/*
+ 	 * if requesting whole line but some other field has been altered,
+ 	 * then the whole line must be rebuilt
+ 	 */
+ 	if (num == 0 && (node0_valid == 0 || assign)) {
+ 		/* first, parse remainder of input record */
+ 		if (NF_node->var_value->numbr == -1) {
+ 			if (parse_high_water == 0)
+ 				parse_extent = node0.stptr;
+ 			n = parse_fields(HUGE-1, &parse_extent,
+ 		    		node0.stlen - (parse_extent - node0.stptr),
+ 		    		save_fs, set_field, (NODE *)NULL);
+ 			assign_number(&NF_node->var_value, (AWKNUM)n);
+ 		}
+ 		if (node0_valid == 0)
+ 			rebuild_record();
+ 		return &fields_arr[0];
+ 	}
+ 	if (num > 0 && assign)
+ 		node0_valid = 0;
+ 	if (num <= parse_high_water)	/* we have already parsed this field */
+ 		return &fields_arr[num];
+ 	if (parse_high_water == 0 && num > 0)	/* starting at the beginning */
+ 		parse_extent = fields_arr[0]->stptr;
+ 	/*
+ 	 * parse up to num fields, calling set_field() for each, and saving
+ 	 * in parse_extent the point where the parse left off
+ 	 */
+ 	n = parse_fields(num, &parse_extent,
+ 		fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
+ 		save_fs, set_field, (NODE *)NULL);
+ 	if (num == HUGE-1)
+ 		num = n;
+ 	if (n < num) {	/* requested field number beyond end of record;
+ 			 * set_field will just extend the number of fields,
+ 			 * with empty fields
+ 			 */
+ 		set_field(num, f_empty, 0, (NODE *) NULL);
+ 		/*
+ 		 * if this field is onthe LHS of an assignment, then we want to
+ 		 * set NF to this value, below
+ 		 */
+ 		if (assign)
+ 			n = num;
+ 	}
+ 	/*
+ 	 * if we reached the end of the record, set NF to the number of fields
+ 	 * so far.  Note that num might actually refer to a field that
+ 	 * is beyond the end of the record, but we won't set NF to that value at
+ 	 * this point, since this is only a reference to the field and NF
+ 	 * only gets set if the field is assigned to -- in this case n has
+ 	 * been set to num above
+ 	 */
+ 	if (*parse_extent == '\0')
+ 		assign_number(&NF_node->var_value, (AWKNUM)n);
+ 
+ 	return &fields_arr[num];
+ }
+ 
+ /*
+  * this is called both from get_field() and from do_split()
+  */
+ static int
+ parse_fields(up_to, buf, len, fs, set, n)
+ int up_to;	/* parse only up to this field number */
+ char **buf;	/* on input: string to parse; on output: point to start next */
+ int len;
+ register char *fs;
+ void (*set) ();	/* routine to set the value of the parsed field */
+ NODE *n;
+ {
+ 	char *s = *buf;
+ 	register char *field;
+ 	register char *scan;
+ 	register char *end = s + len;
+ 	int NF = parse_high_water;
+ 	char rs = get_rs();
+ 
+ 
+ 	if (up_to == HUGE)
+ 		NF = 0;
+ 	if (*fs && *(fs + 1) != '\0') {	/* fs is a regexp */
+ 		struct re_registers reregs;
+ 
+ 		scan = s;
+ 		if (rs == 0 && STREQ(FS_node->var_value->stptr, " ")) {
+ 			while ((*scan == '\n' || *scan == ' ' || *scan == '\t')
+ 			    && scan < end)
+ 				scan++;
+ 		}
+ 		s = scan;
+ 		while (scan < end
+ 		    && re_split(scan, (int)(end - scan), fs, &reregs) != -1
+ 		    && NF < up_to) {
+ 			if (reregs.end[0] == 0) {	/* null match */
+ 				scan++;
+ 				if (scan == end) {
+ 					(*set)(++NF, s, scan - s, n);
+ 					up_to = NF;
+ 					break;
+ 				}
+ 				continue;
+ 			}
+ 			(*set)(++NF, s, scan - s + reregs.start[0], n);
+ 			scan += reregs.end[0];
+ 			s = scan;
+ 		}
+ 		if (NF != up_to && scan <= end) {
+ 			if (!(rs == 0 && scan == end)) {
+ 				(*set)(++NF, scan, (int)(end - scan), n);
+ 				scan = end;
+ 			}
+ 		}
+ 		*buf = scan;
+ 		return (NF);
+ 	}
+ 	for (scan = s; scan < end && NF < up_to; scan++) {
+ 		/*
+ 		 * special case:  fs is single space, strip leading
+ 		 * whitespace 
+ 		 */
+ 		if (*fs == ' ') {
+ 			while ((*scan == ' ' || *scan == '\t') && scan < end)
+ 				scan++;
+ 			if (scan >= end)
+ 				break;
+ 		}
+ 		field = scan;
+ 		if (*fs == ' ')
+ 			while (*scan != ' ' && *scan != '\t' && scan < end)
+ 				scan++;
+ 		else {
+ 			while (*scan != *fs && scan < end)
+ 				scan++;
+ 			if (rs && scan == end-1 && *scan == *fs) {
+ 				(*set)(++NF, field, (int)(scan - field), n);
+ 				field = scan;
+ 			}
+ 		}
+ 		(*set)(++NF, field, (int)(scan - field), n);
+ 		if (scan == end)
+ 			break;
+ 	}
+ 	*buf = scan;
+ 	return NF;
+ }
+ 
+ static int
+ re_split(buf, len, fs, reregsp)
+ char *buf, *fs;
+ int len;
+ struct re_registers *reregsp;
+ {
+ 	typedef struct re_pattern_buffer RPAT;
+ 	static RPAT *rp;
+ 	static char *last_fs = NULL;
+ 
+ 	if ((last_fs != NULL && !STREQ(fs, last_fs))
+ 	    || (rp && ! strict && ((IGNORECASE_node->var_value->numbr != 0)
+ 			 ^ (rp->translate != NULL))))
+ 	{
+ 		/* fs has changed or IGNORECASE has changed */
+ 		free(rp->buffer);
+ 		free(rp->fastmap);
+ 		free((char *) rp);
+ 		free(last_fs);
+ 		last_fs = NULL;
+ 	}
+ 	if (last_fs == NULL) {	/* first time */
+ 		emalloc(rp, RPAT *, sizeof(RPAT), "re_split");
+ 		memset((char *) rp, 0, sizeof(RPAT));
+ 		emalloc(rp->buffer, char *, 8, "re_split");
+ 		rp->allocated = 8;
+ 		emalloc(rp->fastmap, char *, 256, "re_split");
+ 		emalloc(last_fs, char *, strlen(fs) + 1, "re_split");
+ 		(void) strcpy(last_fs, fs);
+ 		if (! strict && IGNORECASE_node->var_value->numbr != 0.0)
+ 			rp->translate = casetable;
+ 		else
+ 			rp->translate = NULL;
+ 		if (re_compile_pattern(fs, strlen(fs), rp) != NULL)
+ 			fatal("illegal regular expression for FS: `%s'", fs);
+ 	}
+ 	return re_search(rp, buf, len, 0, len, reregsp);
+ }
+ 
+ NODE *
+ do_split(tree)
+ NODE *tree;
+ {
+ 	NODE *t1, *t2, *t3;
+ 	register char *splitc;
+ 	char *s;
+ 	NODE *n;
+ 
+ 	if (a_get_three(tree, &t1, &t2, &t3) < 3)
+ 		splitc = get_fs();
+ 	else
+ 		splitc = force_string(t3)->stptr;
+ 
+ 	n = t2;
+ 	if (t2->type == Node_param_list)
+ 		n = stack_ptr[t2->param_cnt];
+ 	if (n->type != Node_var && n->type != Node_var_array)
+ 		fatal("second argument of split is not a variable");
+ 	assoc_clear(n);
+ 
+ 	tree = force_string(t1);
+ 
+ 	s = tree->stptr;
+ 	return tmp_number((AWKNUM)
+ 		parse_fields(HUGE, &s, tree->stlen, splitc, set_element, n));
+ }
+ 
+ static char *
+ get_fs()
+ {
+ 	register NODE *tmp;
+ 	static char buf[10];
+ 
+ 	tmp = force_string(FS_node->var_value);
+ 	if (get_rs() == 0) {
+ 		if (tmp->stlen == 1) {
+ 			if (tmp->stptr[0] == ' ')
+ 				(void) strcpy(buf, "[ 	\n]+");
+ 			else
+ 				sprintf(buf, "[%c\n]", tmp->stptr[0]);
+ 		} else if (tmp->stlen == 0) {
+ 			buf[0] = '\n';
+ 			buf[1] = '\0';
+ 		} else
+ 			return tmp->stptr;
+ 		return buf;
+ 	}
+ 	return tmp->stptr;
+ }
+ 
+ static void
+ set_element(num, s, len, n)
+ int num;
+ char *s;
+ int len;
+ NODE *n;
+ {
+ 	*assoc_lookup(n, tmp_number((AWKNUM) (num))) = make_string(s, len);
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/gawk.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/gawk.h:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/gawk.h	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,642 ----
+ /*
+  * awk.h -- Definitions for gawk. 
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ /* ------------------------------ Includes ------------------------------ */
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <setjmp.h>
+ //#include <varargs.h>
+ #include <stdarg.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <errno.h>
+ 
+ #include "regex.h"
+ 
+ /* ------------------- System Functions, Variables, etc ------------------- */
+ /* nasty nasty SunOS-ism */
+ #ifdef sparc
+ #include <alloca.h>
+ #ifdef lint
+ extern char *alloca();
+ #endif
+ #else
+ extern char *alloca();
+ #endif
+ #ifdef SPRINTF_INT
+ extern int sprintf();
+ #else	/* not USG */
+ /* nasty nasty berkelixm */
+ #define setjmp	_setjmp
+ #define longjmp	_longjmp
+ 
+ extern int sprintf();
+ #endif
+ /*
+  * if you don't have vprintf, but you are BSD, the version defined in
+  * vprintf.c should do the trick.  Otherwise, use this and cross your fingers.
+  */
+ #if defined(VPRINTF_MISSING) && !defined(DOPRNT_MISSING) && !defined(BSDSTDIO)
+ #define vfprintf(fp,fmt,arg)	_doprnt((fmt), (arg), (fp))
+ #endif
+ 
+ #if 0
+ #ifdef __STDC__
+ extern void *malloc(unsigned), *realloc(void *, unsigned);
+ /* LLVM - Changed this to match Linux/Solaris free() */
+ extern void free(void *);
+ /* LLVM - Fixed prototype */
+ extern char *getenv(const char *);
+ 
+ extern char *strcpy(char *, char *), *strcat(char *, char *), *strncpy(char *, char *, int);
+ extern int strcmp(char *, char *);
+ extern int strncmp(char *, char *, int);
+ extern int strncasecmp(char *, char *, int);
+ extern char *strerror(int);
+ extern char *strchr(char *, int);
+ extern int strlen(char *);
+ extern	char *memcpy(char *, char *, int);
+ extern	int memcmp(char *, char *, int);
+ extern	char *memset(char *, int, int);
+ 
+ /* extern int fprintf(FILE *, char *, ...); */
+ extern int fprintf();
+ extern int vfprintf();
+ #ifndef MSDOS
+ extern unsigned int fwrite(const void *, unsigned int, unsigned int, FILE *);
+ #endif
+ extern int fflush(FILE *);
+ extern int fclose(FILE *);
+ extern int pclose(FILE *);
+ #ifndef MSDOS
+ extern int fputs(const char *, FILE *);
+ #endif
+ extern void abort();
+ extern int isatty(int);
+ extern void exit(int);
+ /* LLVM - Fixed prototype */
+ extern int system(const char *);
+ extern int sscanf(/* char *, char *, ... */);
+ 
+ /* LLVM - Fixed prototype */
+ extern double atof(const char *);
+ extern int fstat(int, struct stat *);
+ extern off_t lseek(int, off_t, int);
+ extern int fseek(FILE *, long, int);
+ extern int close(int);
+ #endif
+ /* LLVM - Get rid of these prototypes */
+ #if 0
+ extern int open();
+ extern int pipe(int *);
+ extern int dup2(int, int);
+ #endif
+ 
+ #if 0
+ #ifndef MSDOS
+ extern int unlink(char *);
+ #endif
+ extern int fork();
+ extern int execl(/* char *, char *, ... */);
+ extern int read(int, char *, int);
+ extern int wait(int *);
+ extern void _exit(int);
+ #else
+ extern void _exit();
+ extern int wait();
+ extern int read();
+ extern int execl();
+ extern int fork();
+ extern int unlink();
+ extern int dup2();
+ extern int pipe();
+ extern int open();
+ extern int close();
+ extern int fseek();
+ extern off_t lseek();
+ extern int fstat();
+ extern void exit();
+ extern int system();
+ extern int isatty();
+ extern void abort();
+ extern int fputs();
+ extern int fclose();
+ extern int pclose();
+ extern int fflush();
+ extern int fwrite();
+ extern int fprintf();
+ extern int vfprintf();
+ extern int sscanf();
+ extern char *malloc(), *realloc();
+ extern void free();
+ extern char *getenv();
+ 
+ extern int strcmp();
+ extern int strncmp();
+ extern int strncasecmp();
+ extern int strlen();
+ extern char *strcpy(), *strcat(), *strncpy();
+ extern	char *memset();
+ extern	int memcmp();
+ extern	char *memcpy();
+ extern char *strerror();
+ extern char *strchr();
+ 
+ extern double atof();
+ #endif
+ #endif
+ 
+ #ifndef MSDOS
+ extern int errno;
+ #endif	/* MSDOS */
+ 
+ /* ------------------ Constants, Structures, Typedefs  ------------------ */
+ #define AWKNUM	double
+ 
+ typedef enum {
+ 	/* illegal entry == 0 */
+ 	Node_illegal,
+ 
+ 	/* binary operators  lnode and rnode are the expressions to work on */
+ 	Node_times,
+ 	Node_quotient,
+ 	Node_mod,
+ 	Node_plus,
+ 	Node_minus,
+ 	Node_cond_pair,		/* conditional pair (see Node_line_range) */
+ 	Node_subscript,
+ 	Node_concat,
+ 	Node_exp,
+ 
+ 	/* unary operators   subnode is the expression to work on */
+ /*10*/	Node_preincrement,
+ 	Node_predecrement,
+ 	Node_postincrement,
+ 	Node_postdecrement,
+ 	Node_unary_minus,
+ 	Node_field_spec,
+ 
+ 	/* assignments   lnode is the var to assign to, rnode is the exp */
+ 	Node_assign,
+ 	Node_assign_times,
+ 	Node_assign_quotient,
+ 	Node_assign_mod,
+ /*20*/	Node_assign_plus,
+ 	Node_assign_minus,
+ 	Node_assign_exp,
+ 
+ 	/* boolean binaries   lnode and rnode are expressions */
+ 	Node_and,
+ 	Node_or,
+ 
+ 	/* binary relationals   compares lnode and rnode */
+ 	Node_equal,
+ 	Node_notequal,
+ 	Node_less,
+ 	Node_greater,
+ 	Node_leq,
+ /*30*/	Node_geq,
+ 	Node_match,
+ 	Node_nomatch,
+ 
+ 	/* unary relationals   works on subnode */
+ 	Node_not,
+ 
+ 	/* program structures */
+ 	Node_rule_list,		/* lnode is a rule, rnode is rest of list */
+ 	Node_rule_node,		/* lnode is pattern, rnode is statement */
+ 	Node_statement_list,	/* lnode is statement, rnode is more list */
+ 	Node_if_branches,	/* lnode is to run on true, rnode on false */
+ 	Node_expression_list,	/* lnode is an exp, rnode is more list */
+ 	Node_param_list,	/* lnode is a variable, rnode is more list */
+ 
+ 	/* keywords */
+ /*40*/	Node_K_if,		/* lnode is conditonal, rnode is if_branches */
+ 	Node_K_while,		/* lnode is condtional, rnode is stuff to run */
+ 	Node_K_for,		/* lnode is for_struct, rnode is stuff to run */
+ 	Node_K_arrayfor,	/* lnode is for_struct, rnode is stuff to run */
+ 	Node_K_break,		/* no subs */
+ 	Node_K_continue,	/* no stuff */
+ 	Node_K_print,		/* lnode is exp_list, rnode is redirect */
+ 	Node_K_printf,		/* lnode is exp_list, rnode is redirect */
+ 	Node_K_next,		/* no subs */
+ 	Node_K_exit,		/* subnode is return value, or NULL */
+ 	Node_K_do,		/* lnode is conditional, rnode stuff to run */
+ 	Node_K_return,
+ 	Node_K_delete,
+ 	Node_K_getline,
+ 	Node_K_function,	/* lnode is statement list, rnode is params */
+ 
+ 	/* I/O redirection for print statements */
+ 	Node_redirect_output,	/* subnode is where to redirect */
+ 	Node_redirect_append,	/* subnode is where to redirect */
+ 	Node_redirect_pipe,	/* subnode is where to redirect */
+ 	Node_redirect_pipein,	/* subnode is where to redirect */
+ 	Node_redirect_input,	/* subnode is where to redirect */
+ 
+ 	/* Variables */
+ 	Node_var,		/* rnode is value, lnode is array stuff */
+ 	Node_var_array,		/* array is ptr to elements, asize num of
+ 				 * eles */
+ 	Node_val,		/* node is a value - type in flags */
+ 
+ 	/* Builtins   subnode is explist to work on, proc is func to call */
+ 	Node_builtin,
+ 
+ 	/*
+ 	 * pattern: conditional ',' conditional ;  lnode of Node_line_range
+ 	 * is the two conditionals (Node_cond_pair), other word (rnode place)
+ 	 * is a flag indicating whether or not this range has been entered.
+ 	 */
+ 	Node_line_range,
+ 
+ 	/*
+ 	 * boolean test of membership in array lnode is string-valued
+ 	 * expression rnode is array name 
+ 	 */
+ 	Node_in_array,
+ 
+ 	Node_func,		/* lnode is param. list, rnode is body */
+ 	Node_func_call,		/* lnode is name, rnode is argument list */
+ 
+ 	Node_cond_exp,		/* lnode is conditonal, rnode is if_branches */
+ 	Node_regex,
+ 	Node_hashnode,
+ 	Node_ahash,
+ } NODETYPE;
+ 
+ /*
+  * NOTE - this struct is a rather kludgey -- it is packed to minimize
+  * space usage, at the expense of cleanliness.  Alter at own risk.
+  */
+ typedef struct exp_node {
+ 	union {
+ 		struct {
+ 			union {
+ 				struct exp_node *lptr;
+ 				char *param_name;
+ 				char *retext;
+ 				struct exp_node *nextnode;
+ 			} l;
+ 			union {
+ 				struct exp_node *rptr;
+ 				struct exp_node *(*pptr) ();
+ 				struct re_pattern_buffer *preg;
+ 				struct for_loop_header *hd;
+ 				struct exp_node **av;
+ 				int r_ent;	/* range entered */
+ 			} r;
+ 			char *name;
+ 			short number;
+ 			unsigned char recase;
+ 		} nodep;
+ 		struct {
+ 			AWKNUM fltnum;	/* this is here for optimal packing of
+ 					 * the structure on many machines
+ 					 */
+ 			char *sp;
+ 			short slen;
+ 			unsigned char sref;
+ 		} val;
+ 		struct {
+ 			struct exp_node *next;
+ 			char *name;
+ 			int length;
+ 			struct exp_node *value;
+ 		} hash;
+ #define	hnext	sub.hash.next
+ #define	hname	sub.hash.name
+ #define	hlength	sub.hash.length
+ #define	hvalue	sub.hash.value
+ 		struct {
+ 			struct exp_node *next;
+ 			struct exp_node *name;
+ 			struct exp_node *value;
+ 		} ahash;
+ #define	ahnext	sub.ahash.next
+ #define	ahname	sub.ahash.name
+ #define	ahvalue	sub.ahash.value
+ 	} sub;
+ 	NODETYPE type;
+ 	unsigned char flags;
+ #			define	MEM	0x7
+ #			define	MALLOC	1	/* can be free'd */
+ #			define	TEMP	2	/* should be free'd */
+ #			define	PERM	4	/* can't be free'd */
+ #			define	VAL	0x18
+ #			define	NUM	8	/* numeric value is valid */
+ #			define	STR	16	/* string value is valid */
+ #			define	NUMERIC	32	/* entire field is numeric */
+ } NODE;
+ 
+ #define lnode	sub.nodep.l.lptr
+ #define nextp	sub.nodep.l.nextnode
+ #define rnode	sub.nodep.r.rptr
+ #define source_file	sub.nodep.name
+ #define	source_line	sub.nodep.number
+ #define	param_cnt	sub.nodep.number
+ #define param	sub.nodep.l.param_name
+ 
+ #define subnode	lnode
+ #define proc	sub.nodep.r.pptr
+ 
+ #define reexp	lnode
+ #define rereg	sub.nodep.r.preg
+ #define re_case sub.nodep.recase
+ #define re_text sub.nodep.l.retext
+ 
+ #define forsub	lnode
+ #define forloop	rnode->sub.nodep.r.hd
+ 
+ #define stptr	sub.val.sp
+ #define stlen	sub.val.slen
+ #define stref	sub.val.sref
+ #define	valstat	flags
+ 
+ #define numbr	sub.val.fltnum
+ 
+ #define var_value lnode
+ #define var_array sub.nodep.r.av
+ 
+ #define condpair lnode
+ #define triggered sub.nodep.r.r_ent
+ 
+ #define HASHSIZE 101
+ 
+ typedef struct for_loop_header {
+ 	NODE *init;
+ 	NODE *cond;
+ 	NODE *incr;
+ } FOR_LOOP_HEADER;
+ 
+ /* for "for(iggy in foo) {" */
+ struct search {
+ 	int numleft;
+ 	NODE **arr_ptr;
+ 	NODE *bucket;
+ 	NODE *retval;
+ };
+ 
+ /* for faster input, bypass stdio */
+ typedef struct iobuf {
+ 	int fd;
+ 	char *buf;
+ 	char *off;
+ 	int size;	/* this will be determined by an fstat() call */
+ 	int cnt;
+ 	char *secbuf;
+ 	int secsiz;
+ 	int flag;
+ #	define		IOP_IS_TTY	1
+ } IOBUF;
+ 
+ /*
+  * structure used to dynamically maintain a linked-list of open files/pipes
+  */
+ struct redirect {
+ 	int flag;
+ #		define		RED_FILE	1
+ #		define		RED_PIPE	2
+ #		define		RED_READ	4
+ #		define		RED_WRITE	8
+ #		define		RED_APPEND	16
+ #		define		RED_NOBUF	32
+ 	char *value;
+ 	FILE *fp;
+ 	IOBUF *iop;
+ 	int pid;
+ 	int status;
+ 	long offset;		/* used for dynamic management of open files */
+ 	struct redirect *prev;
+ 	struct redirect *next;
+ };
+ 
+ /* longjmp return codes, must be nonzero */
+ /* Continue means either for loop/while continue, or next input record */
+ #define TAG_CONTINUE 1
+ /* Break means either for/while break, or stop reading input */
+ #define TAG_BREAK 2
+ /* Return means return from a function call; leave value in ret_node */
+ #define	TAG_RETURN 3
+ 
+ #ifdef MSDOS
+ #define HUGE	0x7fff
+ #else
+ #define HUGE	0x7fffffff
+ #endif
+ 
+ /* -------------------------- External variables -------------------------- */
+ /* gawk builtin variables */
+ extern NODE *FS_node, *NF_node, *RS_node, *NR_node;
+ extern NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
+ extern NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
+ extern NODE *IGNORECASE_node;
+ 
+ extern NODE **stack_ptr;
+ extern NODE *Nnull_string;
+ extern NODE *deref;
+ extern NODE **fields_arr;
+ extern int sourceline;
+ extern char *source;
+ extern NODE *expression_value;
+ 
+ extern NODE *variables[];
+ 
+ extern NODE *_t;	/* used as temporary in tree_eval */
+ 
+ extern char *myname;
+ 
+ extern int node0_valid;
+ extern int field_num;
+ extern int strict;
+ 
+ /* ------------------------- Pseudo-functions ------------------------- */
+ #define is_identchar(c) (isalnum(c) || (c) == '_')
+ 
+ 
+ #define	free_temp(n)	if ((n)->flags&TEMP) { deref = (n); do_deref(); } else
+ #define	tree_eval(t)	(_t = (t),(_t) == NULL ? Nnull_string : \
+ 			((_t)->type == Node_val ? (_t) : r_tree_eval((_t))))
+ #define	make_string(s,l)	make_str_node((s),(l),0)
+ 
+ #define	cant_happen()	fatal("line %d, file: %s; bailing out", \
+ 				__LINE__, __FILE__);
+ #ifdef MEMDEBUG
+ #define memmsg(x,y,z,zz)	fprintf(stderr, "malloc: %s: %s: %d %0x\n", z, x, y, zz)
+ #define free(s)	fprintf(stderr, "free: s: %0x\n", s), do_free(s)
+ #else
+ #define memmsg(x,y,z,zz)
+ #endif
+ 
+ #ifdef BWGC
+ #define	emalloc(var,ty,x,str)	if ((var = (ty) GC_malloc((unsigned)((x)==0?1:(x)))) == NULL)\
+ 				    fatal("%s: %s: can't allocate memory (%s)",\
+ 					(str), "var", strerror(errno)); else\
+ 				    memmsg("var", x, str, var)
+ #define	erealloc(var,ty,x,str)	if((var=(ty)GC_realloc((char *)var,\
+ 						(unsigned)(x)))==NULL)\
+ 				    fatal("%s: %s: can't allocate memory (%s)",\
+ 					(str), "var", strerror(errno)); else\
+ 				    memmsg("re: var", x, str, var)
+ #else
+ #define	emalloc(var,ty,x,str)	if ((var = (ty) malloc((unsigned)(x))) == NULL)\
+ 				    fatal("%s: %s: can't allocate memory (%s)",\
+ 					(str), "var", strerror(errno)); else\
+ 				    memmsg("var", x, str, var)
+ #define	erealloc(var,ty,x,str)	if((var=(ty)realloc((char *)var,\
+ 						(unsigned)(x)))==NULL)\
+ 				    fatal("%s: %s: can't allocate memory (%s)",\
+ 					(str), "var", strerror(errno)); else\
+ 				    memmsg("re: var", x, str, var)
+ #endif BWGC
+ #ifdef DEBUG
+ #define	force_number	r_force_number
+ #define	force_string	r_force_string
+ #else
+ #ifdef lint
+ extern AWKNUM force_number();
+ #endif
+ #ifdef MSDOS
+ extern double _msc51bug;
+ #define	force_number(n)	(_msc51bug=(_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t)))
+ #else
+ #define	force_number(n)	(_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t))
+ #endif
+ #define	force_string(s)	(_t = (s),(_t->flags & STR) ? _t : r_force_string(_t))
+ #endif
+ 
+ #define	STREQ(a,b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
+ #define	STREQN(a,b,n)	((n) && *(a) == *(b) && strncmp((a), (b), (n)) == 0)
+ 
+ #define	WHOLELINE	(node0_valid ? fields_arr[0] : *get_field(0,0))
+ 
+ /* ------------- Function prototypes or defs (as appropriate) ------------- */
+ #ifdef __STDC__
+ extern	int parse_escape(char **);
+ extern	int devopen(char *, char *);
+ extern	struct re_pattern_buffer *make_regexp(NODE *, int);
+ extern	struct re_pattern_buffer *mk_re_parse(char *, int);
+ extern	NODE *variable(char *);
+ extern	NODE *install(NODE **, char *, NODE *);
+ extern	NODE *lookup(NODE **, char *);
+ extern	NODE *make_name(char *, NODETYPE);
+ extern	int interpret(NODE *);
+ extern	NODE *r_tree_eval(NODE *);
+ extern	void assign_number(NODE **, double);
+ extern	int cmp_nodes(NODE *, NODE *);
+ extern	struct redirect *redirect(NODE *, int *);
+ extern	int flush_io(void);
+ extern	void print_simple(NODE *, FILE *);
+ extern	void warning(char *,...);
+ /* extern	void warning(); */
+ extern	void fatal(char *,...);
+ /* extern	void fatal(); */
+ extern	void set_record(char *, int);
+ extern	NODE **get_field(int, int);
+ extern	NODE **get_lhs(NODE *, int);
+ extern	void do_deref(void );
+ extern	struct search *assoc_scan(NODE *);
+ extern	struct search *assoc_next(struct search *);
+ extern	NODE **assoc_lookup(NODE *, NODE *);
+ extern	double r_force_number(NODE *);
+ extern	NODE *r_force_string(NODE *);
+ extern	NODE *newnode(NODETYPE);
+ extern	NODE *dupnode(NODE *);
+ extern	NODE *make_number(double);
+ extern	NODE *tmp_number(double);
+ extern	NODE *make_str_node(char *, int, int);
+ extern	NODE *tmp_string(char *, int);
+ extern	char *re_compile_pattern(char *, int, struct re_pattern_buffer *);
+ extern	int re_search(struct re_pattern_buffer *, char *, int, int, int, struct re_registers *);
+ extern	void freenode(NODE *);
+ 
+ #else
+ extern	int parse_escape();
+ extern	void freenode();
+ extern	int devopen();
+ extern	struct re_pattern_buffer *make_regexp();
+ extern	struct re_pattern_buffer *mk_re_parse();
+ extern	NODE *variable();
+ extern	NODE *install();
+ extern	NODE *lookup();
+ extern	int interpret();
+ extern	NODE *r_tree_eval();
+ extern	void assign_number();
+ extern	int cmp_nodes();
+ extern	struct redirect *redirect();
+ extern	int flush_io();
+ extern	void print_simple();
+ extern	void warning();
+ extern	void fatal();
+ extern	void set_record();
+ extern	NODE **get_field();
+ extern	NODE **get_lhs();
+ extern	void do_deref();
+ extern	struct search *assoc_scan();
+ extern	struct search *assoc_next();
+ extern	NODE **assoc_lookup();
+ extern	double r_force_number();
+ extern	NODE *r_force_string();
+ extern	NODE *newnode();
+ extern	NODE *dupnode();
+ extern	NODE *make_number();
+ extern	NODE *tmp_number();
+ extern	NODE *make_str_node();
+ extern	NODE *tmp_string();
+ extern	char *re_compile_pattern();
+ extern	int re_search();
+ #endif
+ 
+ #if !defined(__STDC__) || __STDC__ <= 0
+ #define volatile
+ #endif
+ 
+ /* Figure out what '\a' really is. */
+ #ifdef __STDC__
+ #define BELL	'\a'		/* sure makes life easy, don't it? */
+ #else
+ #	if 'z' - 'a' == 25	/* ascii */
+ #		if 'a' != 97	/* machine is dumb enough to use mark parity */
+ #			define BELL	'\207'
+ #		else
+ #			define BELL	'\07'
+ #		endif
+ #	else
+ #		define BELL	'\057'
+ #	endif
+ #endif
+ 
+ #ifndef SIGTYPE
+ #define SIGTYPE	void
+ #endif
+ 
+ extern char casetable[];	/* for case-independent regexp matching */
+ 
+ #ifdef BWGC
+ #define	malloc(n)	GC_malloc((n)==0?1:(n))
+ #endif
+ #ifdef IGNOREFREE
+ #define	free(ptr)	{};
+ #endif


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/io.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/io.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:20 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/io.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,811 ----
+ /*
+  * io.c - routines for dealing with input and output and records
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ #ifndef O_RDONLY
+ #include <fcntl.h>
+ #endif
+ #include <signal.h>
+ 
+ extern FILE *popen();
+ 
+ static void do_file();
+ static IOBUF *nextfile();
+ static int get_a_record();
+ static int iop_close();
+ static IOBUF *iop_alloc();
+ static void close_one();
+ static int close_redir();
+ static IOBUF *gawk_popen();
+ static int gawk_pclose();
+ 
+ static struct redirect *red_head = NULL;
+ static int getline_redirect = 0;	/* "getline <file" being executed */
+ 
+ extern char *line_buf;
+ extern int output_is_tty;
+ extern NODE *ARGC_node;
+ extern NODE *ARGV_node;
+ extern NODE **fields_arr;
+ 
+ int field_num;
+ 
+ static IOBUF *
+ nextfile()
+ {
+ 	static int i = 1;
+ 	static int files = 0;
+ 	static IOBUF *curfile = NULL;
+ 	char *arg;
+ 	char *cp;
+ 	int fd = -1;
+ 
+ 	if (curfile != NULL && curfile->cnt != EOF)
+ 		return curfile;
+ 	for (; i < (int) (ARGC_node->lnode->numbr); i++) {
+ 		arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr;
+ 		if (*arg == '\0')
+ 			continue;
+ 		cp = strchr(arg, '=');
+ 		if (cp != NULL) {
+ 			*cp++ = '\0';
+ 			variable(arg)->var_value = make_string(cp, strlen(cp));
+ 			*--cp = '=';	/* restore original text of ARGV */
+ 		} else {
+ 			files++;
+ 			if (STREQ(arg, "-"))
+ 				fd = 0;
+ 			else
+ 				fd = devopen(arg, "r");
+ 			if (fd == -1)
+ 				fatal("cannot open file `%s' for reading (%s)",
+ 					arg, strerror(errno));
+ 				/* NOTREACHED */
+ 			/* This is a kludge.  */
+ 			deref = FILENAME_node->var_value;
+ 			do_deref();
+ 			FILENAME_node->var_value =
+ 				make_string(arg, strlen(arg));
+ 			FNR_node->var_value->numbr = 0.0;
+ 			i++;
+ 			break;
+ 		}
+ 	}
+ 	if (files == 0) {
+ 		files++;
+ 		/* no args. -- use stdin */
+ 		/* FILENAME is init'ed to "-" */
+ 		/* FNR is init'ed to 0 */
+ 		fd = 0;
+ 	}
+ 	if (fd == -1)
+ 		return NULL;
+ 	return curfile = iop_alloc(fd);
+ }
+ 
+ static IOBUF *
+ iop_alloc(fd)
+ int fd;
+ {
+ 	IOBUF *iop;
+ 	struct stat stb;
+ 
+ 	/*
+ 	 * System V doesn't have the file system block size in the
+ 	 * stat structure. So we have to make some sort of reasonable
+ 	 * guess. We use stdio's BUFSIZ, since that is what it was
+ 	 * meant for in the first place.
+ 	 */
+ #ifdef BLKSIZE_MISSING
+ #define	DEFBLKSIZE	BUFSIZ
+ #else
+ #define DEFBLKSIZE	(stb.st_blksize ? stb.st_blksize : BUFSIZ)
+ #endif
+ 
+ 	if (fd == -1)
+ 		return NULL;
+ 	emalloc(iop, IOBUF *, sizeof(IOBUF), "nextfile");
+ 	iop->flag = 0;
+ 	if (isatty(fd)) {
+ 		iop->flag |= IOP_IS_TTY;
+ 		iop->size = BUFSIZ;
+ 	} else if (fstat(fd, &stb) == -1)
+ 		fatal("can't stat fd %d (%s)", fd, strerror(errno));
+ 	else if (lseek(fd, 0L, 0) == -1)
+ 		iop->size = DEFBLKSIZE;
+ 	else
+ 		iop->size = (stb.st_size < DEFBLKSIZE ?
+ 				stb.st_size+1 : DEFBLKSIZE);
+ 	errno = 0;
+ 	iop->fd = fd;
+ 	emalloc(iop->buf, char *, iop->size, "nextfile");
+ 	iop->off = iop->buf;
+ 	iop->cnt = 0;
+ 	iop->secsiz = iop->size < BUFSIZ ? iop->size : BUFSIZ;
+ 	emalloc(iop->secbuf, char *, iop->secsiz, "nextfile");
+ 	return iop;
+ }
+ 
+ void
+ do_input()
+ {
+ 	IOBUF *iop;
+ 	extern int exiting;
+ 
+ 	while ((iop = nextfile()) != NULL) {
+ 		do_file(iop);
+ 		if (exiting)
+ 			break;
+ 	}
+ }
+ 
+ static int
+ iop_close(iop)
+ IOBUF *iop;
+ {
+ 	int ret;
+ 
+ 	ret = close(iop->fd);
+ 	if (ret == -1)
+ 		warning("close of fd %d failed (%s)", iop->fd, strerror(errno));
+ 	free(iop->buf);
+ 	free(iop->secbuf);
+ 	free((char *)iop);
+ 	return ret == -1 ? 1 : 0;
+ }
+ 
+ /*
+  * This reads in a record from the input file
+  */
+ static int
+ inrec(iop)
+ IOBUF *iop;
+ {
+ 	int cnt;
+ 	int retval = 0;
+ 
+ 	cnt = get_a_record(&line_buf, iop);
+ 	if (cnt == EOF) {
+ 		cnt = 0;
+ 		retval = 1;
+ 	} else {
+ 		if (!getline_redirect) {
+ 			assign_number(&NR_node->var_value,
+ 			    NR_node->var_value->numbr + 1.0);
+ 			assign_number(&FNR_node->var_value,
+ 			    FNR_node->var_value->numbr + 1.0);
+ 		}
+ 	}
+ 	set_record(line_buf, cnt);
+ 
+ 	return retval;
+ }
+ 
+ static void
+ do_file(iop)
+ IOBUF *iop;
+ {
+ 	/* This is where it spends all its time.  The infamous MAIN LOOP */
+ 	if (inrec(iop) == 0)
+ 		while (interpret(expression_value) && inrec(iop) == 0)
+ 			;
+ 	(void) iop_close(iop);
+ }
+ 
+ int
+ get_rs()
+ {
+ 	register NODE *tmp;
+ 
+ 	tmp = force_string(RS_node->var_value);
+ 	if (tmp->stlen == 0)
+ 		return 0;
+ 	return *(tmp->stptr);
+ }
+ 
+ /* Redirection for printf and print commands */
+ struct redirect *
+ redirect(tree, errflg)
+ NODE *tree;
+ int *errflg;
+ {
+ 	register NODE *tmp;
+ 	register struct redirect *rp;
+ 	register char *str;
+ 	int tflag = 0;
+ 	int outflag = 0;
+ 	char *direction = "to";
+ 	char *mode;
+ 	int fd;
+ 
+ 	switch (tree->type) {
+ 	case Node_redirect_append:
+ 		tflag = RED_APPEND;
+ 	case Node_redirect_output:
+ 		outflag = (RED_FILE|RED_WRITE);
+ 		tflag |= outflag;
+ 		break;
+ 	case Node_redirect_pipe:
+ 		tflag = (RED_PIPE|RED_WRITE);
+ 		break;
+ 	case Node_redirect_pipein:
+ 		tflag = (RED_PIPE|RED_READ);
+ 		break;
+ 	case Node_redirect_input:
+ 		tflag = (RED_FILE|RED_READ);
+ 		break;
+ 	default:
+ 		fatal ("invalid tree type %d in redirect()", tree->type);
+ 		break;
+ 	}
+ 	tmp = force_string(tree_eval(tree->subnode));
+ 	str = tmp->stptr;
+ 	for (rp = red_head; rp != NULL; rp = rp->next)
+ 		if (STREQ(rp->value, str)
+ 		    && ((rp->flag & ~RED_NOBUF) == tflag
+ 			|| (outflag
+ 			    && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
+ 			break;
+ 	if (rp == NULL) {
+ 		emalloc(rp, struct redirect *, sizeof(struct redirect),
+ 			"redirect");
+ 		emalloc(str, char *, tmp->stlen+1, "redirect");
+ 		memcpy(str, tmp->stptr, tmp->stlen+1);
+ 		rp->value = str;
+ 		rp->flag = tflag;
+ 		rp->offset = 0;
+ 		rp->fp = NULL;
+ 		rp->iop = NULL;
+ 		/* maintain list in most-recently-used first order */
+ 		if (red_head)
+ 			red_head->prev = rp;
+ 		rp->prev = NULL;
+ 		rp->next = red_head;
+ 		red_head = rp;
+ 	}
+ 	while (rp->fp == NULL && rp->iop == NULL) {
+ 		mode = NULL;
+ 		errno = 0;
+ 		switch (tree->type) {
+ 		case Node_redirect_output:
+ 			mode = "w";
+ 			break;
+ 		case Node_redirect_append:
+ 			mode = "a";
+ 			break;
+ 		case Node_redirect_pipe:
+ 			if ((rp->fp = popen(str, "w")) == NULL)
+ 				fatal("can't open pipe (\"%s\") for output (%s)",
+ 					str, strerror(errno));
+ 			rp->flag |= RED_NOBUF;
+ 			break;
+ 		case Node_redirect_pipein:
+ 			direction = "from";
+ 			if (gawk_popen(str, rp) == NULL)
+ 				fatal("can't open pipe (\"%s\") for input (%s)",
+ 					str, strerror(errno));
+ 			break;
+ 		case Node_redirect_input:
+ 			direction = "from";
+ 			rp->iop = iop_alloc(devopen(str, "r"));
+ 			break;
+ 		default:
+ 			cant_happen();
+ 		}
+ 		if (mode != NULL) {
+ 			fd = devopen(str, mode);
+ 			if (fd != -1) {
+ 				rp->fp = fdopen(fd, mode);
+ 				if (isatty(fd))
+ 					rp->flag |= RED_NOBUF;
+ 			}
+ 		}
+ 		if (rp->fp == NULL && rp->iop == NULL) {
+ 			/* too many files open -- close one and try again */
+ 			if (errno == ENFILE || errno == EMFILE)
+ 				close_one();
+ 			else {
+ 				/*
+ 				 * Some other reason for failure.
+ 				 *
+ 				 * On redirection of input from a file,
+ 				 * just return an error, so e.g. getline
+ 				 * can return -1.  For output to file,
+ 				 * complain. The shell will complain on
+ 				 * a bad command to a pipe.
+ 				 */
+ 				*errflg = 1;
+ 				if (tree->type == Node_redirect_output
+ 				    || tree->type == Node_redirect_append)
+ 					fatal("can't redirect %s `%s' (%s)",
+ 					    direction, str, strerror(errno));
+ 				else
+ 					return NULL;
+ 			}
+ 		}
+ 	}
+ 	if (rp->offset != 0)	/* this file was previously open */
+ 		if (fseek(rp->fp, rp->offset, 0) == -1)
+ 			fatal("can't seek to %ld on `%s' (%s)",
+ 				rp->offset, str, strerror(errno));
+ 	free_temp(tmp);
+ 	return rp;
+ }
+ 
+ static void
+ close_one()
+ {
+ 	register struct redirect *rp;
+ 	register struct redirect *rplast = NULL;
+ 
+ 	/* go to end of list first, to pick up least recently used entry */
+ 	for (rp = red_head; rp != NULL; rp = rp->next)
+ 		rplast = rp;
+ 	/* now work back up through the list */
+ 	for (rp = rplast; rp != NULL; rp = rp->prev)
+ 		if (rp->fp && (rp->flag & RED_FILE)) {
+ 			rp->offset = ftell(rp->fp);
+ 			if (fclose(rp->fp))
+ 				warning("close of \"%s\" failed (%s).",
+ 					rp->value, strerror(errno));
+ 			rp->fp = NULL;
+ 			break;
+ 		}
+ 	if (rp == NULL)
+ 		/* surely this is the only reason ??? */
+ 		fatal("too many pipes or input files open"); 
+ }
+ 
+ NODE *
+ do_close(tree)
+ NODE *tree;
+ {
+ 	NODE *tmp;
+ 	register struct redirect *rp;
+ 
+ 	tmp = force_string(tree_eval(tree->subnode));
+ 	for (rp = red_head; rp != NULL; rp = rp->next) {
+ 		if (STREQ(rp->value, tmp->stptr))
+ 			break;
+ 	}
+ 	free_temp(tmp);
+ 	if (rp == NULL) /* no match */
+ 		return tmp_number((AWKNUM) 0.0);
+ 	fflush(stdout);	/* synchronize regular output */
+ 	return tmp_number((AWKNUM)close_redir(rp));
+ }
+ 
+ static int
+ close_redir(rp)
+ register struct redirect *rp;
+ {
+ 	int status = 0;
+ 
+ 	if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
+ 		status = pclose(rp->fp);
+ 	else if (rp->fp)
+ 		status = fclose(rp->fp);
+ 	else if (rp->iop) {
+ 		if (rp->flag & RED_PIPE)
+ 			status = gawk_pclose(rp);
+ 		else
+ 			status = iop_close(rp->iop);
+ 
+ 	}
+ 	/* SVR4 awk checks and warns about status of close */
+ 	if (status)
+ 		warning("failure status (%d) on %s close of \"%s\" (%s).",
+ 			status,
+ 			(rp->flag & RED_PIPE) ? "pipe" :
+ 			"file", rp->value, strerror(errno));
+ 	if (rp->next)
+ 		rp->next->prev = rp->prev;
+ 	if (rp->prev)
+ 		rp->prev->next = rp->next;
+ 	else
+ 		red_head = rp->next;
+ 	free(rp->value);
+ 	free((char *)rp);
+ 	return status;
+ }
+ 
+ int
+ flush_io ()
+ {
+ 	register struct redirect *rp;
+ 	int status = 0;
+ 
+ 	errno = 0;
+ 	if (fflush(stdout)) {
+ 		warning("error writing standard output (%s).", strerror(errno));
+ 		status++;
+ 	}
+ 	errno = 0;
+ 	if (fflush(stderr)) {
+ 		warning("error writing standard error (%s).", strerror(errno));
+ 		status++;
+ 	}
+ 	for (rp = red_head; rp != NULL; rp = rp->next)
+ 		/* flush both files and pipes, what the heck */
+ 		if ((rp->flag & RED_WRITE) && rp->fp != NULL)
+ 			if (fflush(rp->fp)) {
+ 				warning("%s flush of \"%s\" failed (%s).",
+ 				    (rp->flag  & RED_PIPE) ? "pipe" :
+ 				    "file", rp->value, strerror(errno));
+ 				status++;
+ 			}
+ 	return status;
+ }
+ 
+ int
+ close_io ()
+ {
+ 	register struct redirect *rp;
+ 	int status = 0;
+ 
+ 	for (rp = red_head; rp != NULL; rp = rp->next)
+ 		if (close_redir(rp))
+ 			status++;
+ 	return status;
+ }
+ 
+ /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
+ int
+ devopen (name, mode)
+ char *name, *mode;
+ {
+ 	int openfd = -1;
+ 	FILE *fdopen ();
+ 	char *cp;
+ 	int flag = 0;
+ 
+ 	switch(mode[0]) {
+ 	case 'r':
+ 		flag = O_RDONLY;
+ 		break;
+ 
+ 	case 'w':
+ 		flag = O_WRONLY|O_CREAT|O_TRUNC;
+ 		break;
+ 
+ 	case 'a':
+ 		flag = O_WRONLY|O_APPEND|O_CREAT;
+ 		break;
+ 	default:
+ 		cant_happen();
+ 	}
+ 
+ #if defined(STRICT) || defined(NO_DEV_FD)
+ 	return (open (name, flag, 0666));
+ #else
+ 	if (strict)
+ 		return (open (name, flag, 0666));
+ 
+ 	if (!STREQN (name, "/dev/", 5))
+ 		return (open (name, flag, 0666));
+ 	else
+ 		cp = name + 5;
+ 		
+ 	/* XXX - first three tests ignore mode */
+ 	if (STREQ(cp, "stdin"))
+ 		return (0);
+ 	else if (STREQ(cp, "stdout"))
+ 		return (1);
+ 	else if (STREQ(cp, "stderr"))
+ 		return (2);
+ 	else if (STREQN(cp, "fd/", 3)) {
+ 		cp += 3;
+ 		if (sscanf (cp, "%d", & openfd) == 1 && openfd >= 0)
+ 			/* got something */
+ 			return openfd;
+ 		else
+ 			return -1;
+ 	} else
+ 		return (open (name, flag, 0666));
+ #endif
+ }
+ 
+ #ifndef MSDOS
+ static IOBUF *
+ gawk_popen(cmd, rp)
+ char *cmd;
+ struct redirect *rp;
+ {
+ 	int p[2];
+ 	register int pid;
+ 
+ 	rp->pid = -1;
+ 	rp->iop = NULL;
+ 	if (pipe(p) < 0)
+ 		return NULL;
+ 	if ((pid = fork()) == 0) {
+ 		close(p[0]);
+ 		dup2(p[1], 1);
+ 		close(p[1]);
+ 		execl("/bin/sh", "sh", "-c", cmd, 0);
+ 		_exit(127);
+ 	}
+ 	if (pid == -1)
+ 		return NULL;
+ 	rp->pid = pid;
+ 	close(p[1]);
+ 	return (rp->iop = iop_alloc(p[0]));
+ }
+ 
+ static int
+ gawk_pclose(rp)
+ struct redirect *rp;
+ {
+ 	SIGTYPE (*hstat)(), (*istat)(), (*qstat)();
+ 	int pid;
+ 	int status;
+ 	struct redirect *redp;
+ 
+ 	iop_close(rp->iop);
+ 	if (rp->pid == -1)
+ 		return rp->status;
+ 	hstat = signal(SIGHUP, SIG_IGN);
+ 	istat = signal(SIGINT, SIG_IGN);
+ 	qstat = signal(SIGQUIT, SIG_IGN);
+ 	for (;;) {
+ 		pid = wait(&status);
+ 		if (pid == -1 && errno == ECHILD)
+ 			break;
+ 		else if (pid == rp->pid) {
+ 			rp->pid = -1;
+ 			rp->status = status;
+ 			break;
+ 		} else {
+ 			for (redp = red_head; redp != NULL; redp = redp->next)
+ 				if (pid == redp->pid) {
+ 					redp->pid = -1;
+ 					redp->status = status;
+ 					break;
+ 				}
+ 		}
+ 	}
+ 	signal(SIGHUP, hstat);
+ 	signal(SIGINT, istat);
+ 	signal(SIGQUIT, qstat);
+ 	return(rp->status);
+ }
+ #else
+ static
+ struct {
+ 	char *command;
+ 	char *name;
+ } pipes[_NFILE];
+ 
+ static IOBUF *
+ gawk_popen(cmd, rp)
+ char *cmd;
+ struct redirect *rp;
+ {
+ 	extern char *strdup(const char *);
+ 	int current;
+ 	char *name;
+ 	static char cmdbuf[256];
+ 
+ 	/* get a name to use.  */
+ 	if ((name = tempnam(".", "pip")) == NULL)
+ 		return NULL;
+ 	sprintf(cmdbuf,"%s > %s", cmd, name);
+ 	system(cmdbuf);
+ 	if ((current = open(name,O_RDONLY)) == -1)
+ 		return NULL;
+ 	pipes[current].name = name;
+ 	pipes[current].command = strdup(cmd);
+ 	return (rp->iop = iop_alloc(current));
+ }
+ 
+ static int
+ gawk_pclose(rp)
+ struct redirect *rp;
+ {
+ 	int cur = rp->iop->fd;
+ 	int rval;
+ 
+ 	rval = iop_close(rp->iop);
+ 
+ 	/* check for an open file  */
+ 	if (pipes[cur].name == NULL)
+ 		return -1;
+ 	unlink(pipes[cur].name);
+ 	free(pipes[cur].name);
+ 	pipes[cur].name = NULL;
+ 	free(pipes[cur].command);
+ 	return rval;
+ }
+ #endif
+ 
+ #define	DO_END_OF_BUF	len = bp - iop->off;\
+ 			used = last - start;\
+ 			while (len + used > iop->secsiz) {\
+ 				iop->secsiz *= 2;\
+ 				erealloc(iop->secbuf,char *,iop->secsiz,"get");\
+ 			}\
+ 			last = iop->secbuf + used;\
+ 			start = iop->secbuf;\
+ 			memcpy(last, iop->off, len);\
+ 			last += len;\
+ 			iop->cnt = read(iop->fd, iop->buf, iop->size);\
+ 			if (iop->cnt < 0)\
+ 				return iop->cnt;\
+ 			end_data = iop->buf + iop->cnt;\
+ 			iop->off = bp = iop->buf;
+ 
+ #define	DO_END_OF_DATA	iop->cnt = read(iop->fd, end_data, end_buf - end_data);\
+ 			if (iop->cnt < 0)\
+ 				return iop->cnt;\
+ 			end_data += iop->cnt;\
+ 			if (iop->cnt == 0)\
+ 				break;\
+ 			iop->cnt = end_data - iop->buf;
+ 
+ static int
+ get_a_record(res, iop)
+ char **res;
+ IOBUF *iop;
+ {
+ 	register char *end_data;
+ 	register char *end_buf;
+ 	char *start;
+ 	register char *bp;
+ 	register char *last;
+ 	int len, used;
+ 	register char rs = get_rs();
+ 
+ 	if (iop->cnt < 0)
+ 		return iop->cnt;
+ 	if ((iop->flag & IOP_IS_TTY) && output_is_tty)
+ 		fflush(stdout);
+ 	end_data = iop->buf + iop->cnt;
+ 	if (iop->off >= end_data) {
+ 		iop->cnt = read(iop->fd, iop->buf, iop->size);
+ 		if (iop->cnt <= 0)
+ 			return iop->cnt = EOF;
+ 		end_data = iop->buf + iop->cnt;
+ 		iop->off = iop->buf;
+ 	}
+ 	last = start = bp = iop->off;
+ 	end_buf = iop->buf + iop->size;
+ 	if (rs == 0) {
+ 		while (!(*bp == '\n' && bp != iop->buf && bp[-1] == '\n')) {
+ 			if (++bp == end_buf) {
+ 				DO_END_OF_BUF
+ 			}
+ 			if (bp == end_data) {
+ 				DO_END_OF_DATA
+ 			}
+ 		}
+ 		if (*bp == '\n' && bp != iop->off && bp[-1] == '\n') {
+ 			int tmp = 0;
+ 
+ 			/* allow for more than two newlines */
+ 			while (*bp == '\n') {
+ 				tmp++;
+ 				if (++bp == end_buf) {
+ 					DO_END_OF_BUF
+ 				}
+ 				if (bp == end_data) {
+ 					DO_END_OF_DATA
+ 				}
+ 			}
+ 			iop->off = bp;
+ 			bp -= 1 + tmp;
+ 		} else if (bp != iop->buf && bp[-1] != '\n') {
+ 			warning("record not terminated");
+ 			iop->off = bp + 2;
+ 		} else {
+ 			bp--;
+ 			iop->off = bp + 2;
+ 		}
+ 	} else {
+ 		while (*bp++ != rs) {
+ 			if (bp == end_buf) {
+ 				DO_END_OF_BUF
+ 			}
+ 			if (bp == end_data) {
+ 				DO_END_OF_DATA
+ 			}
+ 		}
+ 		if (*--bp != rs) {
+ 			warning("record not terminated");
+ 			bp++;
+ 		}
+ 		iop->off = bp + 1;
+ 	}
+ 	if (start == iop->secbuf) {
+ 		len = bp - iop->buf;
+ 		if (len > 0) {
+ 			used = last - start;
+ 			while (len + used > iop->secsiz) {
+ 				iop->secsiz *= 2;
+ 				erealloc(iop->secbuf,char *,iop->secsiz,"get2");
+ 			}
+ 			last = iop->secbuf + used;
+ 			start = iop->secbuf;
+ 			memcpy(last, iop->buf, len);
+ 			last += len;
+ 		}
+ 	} else
+ 		last = bp;
+ 	*last = '\0';
+ 	*res = start;
+ 	return last - start;
+ }
+ 
+ NODE *
+ do_getline(tree)
+ NODE *tree;
+ {
+ 	struct redirect *rp;
+ 	IOBUF *iop;
+ 	int cnt;
+ 	NODE **lhs;
+ 	int redir_error = 0;
+ 
+ 	if (tree->rnode == NULL) {	 /* no redirection */
+ 		iop = nextfile();
+ 		if (iop == NULL)		/* end of input */
+ 			return tmp_number((AWKNUM) 0.0);
+ 	} else {
+ 		rp = redirect(tree->rnode, &redir_error);
+ 		if (rp == NULL && redir_error)	/* failed redirect */
+ 			return tmp_number((AWKNUM) -1.0);
+ 		iop = rp->iop;
+ 		getline_redirect++;
+ 	}
+ 	if (tree->lnode == NULL) {	/* no optional var. -- read in $0 */
+ 		if (inrec(iop) != 0) {
+ 			getline_redirect = 0;
+ 			return tmp_number((AWKNUM) 0.0);
+ 		}
+ 	} else {			/* read in a named variable */
+ 		char *s = NULL;
+ 
+ 		lhs = get_lhs(tree->lnode, 1);
+ 		cnt = get_a_record(&s, iop);
+ 		if (!getline_redirect) {
+ 			assign_number(&NR_node->var_value,
+ 			    NR_node->var_value->numbr + 1.0);
+ 			assign_number(&FNR_node->var_value,
+ 			    FNR_node->var_value->numbr + 1.0);
+ 		}
+ 		if (cnt == EOF) {
+ 			getline_redirect = 0;
+ 			free(s);
+ 			return tmp_number((AWKNUM) 0.0);
+ 		}
+ 		*lhs = make_string(s, strlen(s));
+ 		do_deref();
+ 		/* we may have to regenerate $0 here! */
+ 		if (field_num == 0)
+ 			set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
+ 		field_num = -1;
+ 	}
+ 	getline_redirect = 0;
+ 	return tmp_number((AWKNUM) 1.0);
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/main.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/main.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/main.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,567 ----
+ /*
+  * main.c -- Expression tree constructors and main program for gawk. 
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ #include "patchlevel.h"
+ #include <signal.h>
+ 
+ extern int yyparse();
+ extern void do_input();
+ extern int close_io();
+ extern void init_fields();
+ extern int getopt();
+ extern int re_set_syntax();
+ extern NODE *node();
+ 
+ static void usage();
+ static void set_fs();
+ static void init_vars();
+ static void init_args();
+ static NODE *spc_var();
+ static void pre_assign();
+ static void copyleft();
+ 
+ /* These nodes store all the special variables AWK uses */
+ NODE *FS_node, *NF_node, *RS_node, *NR_node;
+ NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
+ NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
+ NODE *ENVIRON_node, *IGNORECASE_node;
+ NODE *ARGC_node, *ARGV_node;
+ 
+ /*
+  * The parse tree and field nodes are stored here.  Parse_end is a dummy item
+  * used to free up unneeded fields without freeing the program being run 
+  */
+ int errcount = 0;	/* error counter, used by yyerror() */
+ 
+ /* The global null string */
+ NODE *Nnull_string;
+ 
+ /* The name the program was invoked under, for error messages */
+ char *myname;
+ 
+ /* A block of AWK code to be run before running the program */
+ NODE *begin_block = 0;
+ 
+ /* A block of AWK code to be run after the last input file */
+ NODE *end_block = 0;
+ 
+ int exiting = 0;		/* Was an "exit" statement executed? */
+ int exit_val = 0;		/* optional exit value */
+ 
+ #ifdef DEBUG
+ /* non-zero means in debugging is enabled.  Probably not very useful */
+ int debugging = 0;
+ extern int yydebug;
+ #endif
+ 
+ int tempsource = 0;		/* source is in a temp file */
+ char **sourcefile = NULL;	/* source file name(s) */
+ int numfiles = -1;		/* how many source files */
+ 
+ int strict = 0;			/* turn off gnu extensions */
+ 
+ int output_is_tty = 0;		/* control flushing of output */
+ 
+ NODE *expression_value;
+ 
+ /*
+  * for strict to work, legal options must be first
+  *
+  * Unfortunately, -a and -e are orthogonal to -c.
+  */
+ #define EXTENSIONS	8	/* where to clear */
+ #ifdef DEBUG
+ char awk_opts[] = "F:f:v:caeCVdD";
+ #else
+ char awk_opts[] = "F:f:v:caeCV";
+ #endif
+ 
+ char * version_string = "GAWK for MallocBench";
+ 
+ int
+ main(argc, argv)
+ int argc;
+ char **argv;
+ {
+ #ifdef DEBUG
+ 	/* Print out the parse tree.   For debugging */
+ 	register int dotree = 0;
+ #endif
+ #if 0
+ /* LLVM - Don't need this */
+ 	extern char *version_string;
+ #endif
+ 	FILE *fp;
+ 	int c;
+ 	extern int opterr, optind;
+ 	extern char *optarg;
+  	extern char *strrchr();
+  	extern char *tmpnam();
+ 	extern SIGTYPE catchsig();
+ 	int i;
+ 	int nostalgia;
+ #ifdef somtime_in_the_future
+ 	int regex_mode = RE_SYNTAX_POSIX_EGREP;
+ #else
+ 	int regex_mode = RE_SYNTAX_AWK;
+ #endif
+ 
+ 	(void) signal(SIGFPE, catchsig);
+ 	(void) signal(SIGSEGV, catchsig);
+ 
+ #ifdef BWGC
+ 	{
+ 	    extern gc_init();
+ /*	    gc_init();
+ */
+ 	}
+ #endif BWGC
+ 	
+ 	if (strncmp(version_string, "@(#)", 4) == 0)
+ 		version_string += 4;
+ 
+ 	myname = strrchr(argv[0], '/');
+ 	if (myname == NULL)
+ 		myname = argv[0];
+ 	else
+ 		myname++;
+ 	if (argc < 2)
+ 		usage();
+ 
+ 	/* initialize the null string */
+ 	Nnull_string = make_string("", 0);
+ 	Nnull_string->numbr = 0.0;
+ 	Nnull_string->type = Node_val;
+ 	Nnull_string->flags = (PERM|STR|NUM|NUMERIC);
+ 
+ 	/* Set up the special variables */
+ 
+ 	/*
+ 	 * Note that this must be done BEFORE arg parsing else -F
+ 	 * breaks horribly 
+ 	 */
+ 	init_vars();
+ 
+ 	/* worst case */
+ 	emalloc(sourcefile, char **, argc * sizeof(char *), "main");
+ 
+ 
+ #ifdef STRICT	/* strict new awk compatibility */
+ 	strict = 1;
+ 	awk_opts[EXTENSIONS] = '\0';
+ #endif
+ 
+ #ifndef STRICT
+ 	/* undocumented feature, inspired by nostalgia, and a T-shirt */
+ 	nostalgia = 0;
+ 	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
+ 		if (argv[i][1] == '-')		/* -- */
+ 			break;
+ 		else if (argv[i][1] == 'c') {	/* compatibility mode */
+ 			nostalgia = 0;
+ 			break;
+ 		} else if (STREQ(&argv[i][1], "nostalgia"))
+ 			nostalgia = 1;
+ 			/* keep looping, in case -c after -nostalgia */
+ 	}
+ 	if (nostalgia) {
+ 		fprintf (stderr, "awk: bailing out near line 1\n");
+ 		abort();
+ 	}
+ #endif
+ 		
+ 	while ((c = getopt (argc, argv, awk_opts)) != EOF) {
+ 		switch (c) {
+ #ifdef DEBUG
+ 		case 'd':
+ 			debugging++;
+ 			dotree++;
+ 			break;
+ 
+ 		case 'D':
+ 			debugging++;
+ 			yydebug = 2;
+ 			break;
+ #endif
+ 
+ #ifndef STRICT
+ 		case 'c':
+ 			strict = 1;
+ 			break;
+ #endif
+ 
+ 		case 'F':
+ 			set_fs(optarg);
+ 			break;
+ 
+ 		case 'f':
+ 			/*
+ 			 * a la MKS awk, allow multiple -f options.
+ 			 * this makes function libraries real easy.
+ 			 * most of the magic is in the scanner.
+ 			 */
+ 			sourcefile[++numfiles] = optarg;
+ 			break;
+ 
+ 		case 'v':
+ 			pre_assign(optarg);
+ 			break;
+ 
+ 		case 'V':
+ 			fprintf(stderr, "%s, patchlevel %d\n",
+ 					version_string, PATCHLEVEL);
+ 			break;
+ 
+ 		case 'C':
+ 			copyleft();
+ 			break;
+ 
+ 		case 'a':	/* use old fashioned awk regexps */
+ 			regex_mode = RE_SYNTAX_AWK;
+ 			break;
+ 
+ 		case 'e':	/* use egrep style regexps, per Posix */
+ 			regex_mode = RE_SYNTAX_POSIX_EGREP;
+ 			break;
+ 
+ 		case '?':
+ 		default:
+ 			/* getopt will print a message for us */
+ 			/* S5R4 awk ignores bad options and keeps going */
+ 			break;
+ 		}
+ 	}
+ 
+ 	/* Tell the regex routines how they should work. . . */
+ 	(void) re_set_syntax(regex_mode);
+ 
+ #ifdef DEBUG
+ 	setbuf(stdout, (char *) NULL);	/* make debugging easier */
+ #endif
+ 	if (isatty(fileno(stdout)))
+ 		output_is_tty = 1;
+ 	/* No -f option, use next arg */
+ 	/* write to temp file and save sourcefile name */
+ 	if (numfiles == -1) {
+ 		int i;
+ 
+ 		if (optind > argc - 1)	/* no args left */
+ 			usage();
+ 		numfiles++;
+ 		i = strlen (argv[optind]);
+ 		if (i == 0) {	/* sanity check */
+ 			fprintf(stderr, "%s: empty program text\n", myname);
+ 			usage();
+ 			/* NOTREACHED */
+ 		}
+ 		sourcefile[0] = tmpnam((char *) NULL);
+ 		if ((fp = fopen (sourcefile[0], "w")) == NULL)
+ 			fatal("could not save source prog in temp file (%s)",
+ 			strerror(errno));
+ 		if (fwrite (argv[optind], 1, i, fp) == 0)
+ 			fatal(
+ 			"could not write source program to temp file (%s)",
+ 			strerror(errno));
+ 		if (argv[optind][i-1] != '\n')
+ 			putc ('\n', fp);
+ 		(void) fclose (fp);
+ 		tempsource++;
+ 		optind++;
+ 	}
+ 	init_args(optind, argc, myname, argv);
+ 
+ 	/* Read in the program */
+ 	if (yyparse() || errcount)
+ 		exit(1);
+ 
+ #ifdef DEBUG
+ 	if (dotree)
+ 		print_parse_tree(expression_value);
+ #endif
+ 	/* Set up the field variables */
+ 	init_fields();
+ 
+ 	if (begin_block)
+ 		(void) interpret(begin_block);
+ 	if (!exiting && (expression_value || end_block))
+ 		do_input();
+ 	if (end_block)
+ 		(void) interpret(end_block);
+ 	if (close_io() != 0 && exit_val == 0)
+ 		exit_val = 1;
+ 	
+ 	exit(exit_val);
+ 	/* NOTREACHED */
+ 	return exit_val;
+ }
+ 
+ static void
+ usage()
+ {
+ 	char *opt1 = " -f progfile [--]";
+ 	char *opt2 = " [--] 'program'";
+ #ifdef STRICT
+ 	char *regops = " [-ae] [-F fs] [-v var=val]"
+ #else
+ 	char *regops = " [-aecCV] [-F fs] [-v var=val]";
+ #endif
+ 
+ 	fprintf(stderr, "usage: %s%s%s file ...\n       %s%s%s file ...\n",
+ 		myname, regops, opt1, myname, regops, opt2);
+ 	exit(11);
+ }
+ 
+ /* Generate compiled regular expressions */
+ struct re_pattern_buffer *
+ make_regexp(s, ignorecase)
+ NODE *s;
+ int ignorecase;
+ {
+ 	struct re_pattern_buffer *rp;
+ 	char *err;
+ 
+ 	emalloc(rp, struct re_pattern_buffer *, sizeof(*rp), "make_regexp");
+ 	memset((char *) rp, 0, sizeof(*rp));
+ 	emalloc(rp->buffer, char *, 16, "make_regexp");
+ 	rp->allocated = 16;
+ 	emalloc(rp->fastmap, char *, 256, "make_regexp");
+ 
+ 	if (! strict && ignorecase)
+ 		rp->translate = casetable;
+ 	else
+ 		rp->translate = NULL;
+ 	if ((err = re_compile_pattern(s->stptr, s->stlen, rp)) != NULL)
+ 		fatal("%s: /%s/", err, s->stptr);
+ 	free_temp(s);
+ 	return rp;
+ }
+ 
+ struct re_pattern_buffer *
+ mk_re_parse(s, ignorecase)
+ char *s;
+ int ignorecase;
+ {
+ 	char *src;
+ 	register char *dest;
+ 	register int c;
+ 	int in_brack = 0;
+ 
+ 	for (dest = src = s; *src != '\0';) {
+ 		if (*src == '\\') {
+ 			c = *++src;
+ 			switch (c) {
+ 			case '/':
+ 			case 'a':
+ 			case 'b':
+ 			case 'f':
+ 			case 'n':
+ 			case 'r':
+ 			case 't':
+ 			case 'v':
+ 			case 'x':
+ 			case '0':
+ 			case '1':
+ 			case '2':
+ 			case '3':
+ 			case '4':
+ 			case '5':
+ 			case '6':
+ 			case '7':
+ 				c = parse_escape(&src);
+ 				if (c < 0)
+ 					cant_happen();
+ 				*dest++ = (char)c;
+ 				break;
+ 			default:
+ 				*dest++ = '\\';
+ 				*dest++ = (char)c;
+ 				src++;
+ 				break;
+ 			}
+ 		} else if (*src == '/' && ! in_brack)
+ 			break;
+ 		else {
+ 			if (*src == '[')
+ 				in_brack = 1;
+ 			else if (*src == ']')
+ 				in_brack = 0;
+ 
+ 			*dest++ = *src++;
+ 		}
+ 	}
+ 	return make_regexp(tmp_string(s, dest-s), ignorecase);
+ }
+ 
+ static void
+ copyleft ()
+ {
+ 	extern char *version_string;
+ 	char *cp;
+ 	static char blurb[] =
+ "Copyright (C) 1989, Free Software Foundation.\n\
+ GNU Awk comes with ABSOLUTELY NO WARRANTY.  This is free software, and\n\
+ you are welcome to distribute it under the terms of the GNU General\n\
+ Public License, which covers both the warranty information and the\n\
+ terms for redistribution.\n\n\
+ You should have received a copy of the GNU General Public License along\n\
+ with this program; if not, write to the Free Software Foundation, Inc.,\n\
+ 675 Mass Ave, Cambridge, MA 02139, USA.\n";
+ 
+ 	fprintf (stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
+ 	fputs(blurb, stderr);
+ 	fflush(stderr);
+ }
+ 
+ static void
+ set_fs(str)
+ char *str;
+ {
+ 	register NODE **tmp;
+ 
+ 	tmp = get_lhs(FS_node, 0);
+ 	/*
+ 	 * Only if in full compatibility mode check for the stupid special
+ 	 * case so -F\t works as documented in awk even though the shell
+ 	 * hands us -Ft.  Bleah!
+ 	 */
+ 	if (strict && str[0] == 't' && str[1] == '\0')
+ 		str[0] = '\t';
+ 	*tmp = make_string(str, 1);
+ 	do_deref();
+ }
+ 
+ static void
+ init_args(argc0, argc, argv0, argv)
+ int argc0, argc;
+ char *argv0;
+ char **argv;
+ {
+ 	int i, j;
+ 	NODE **aptr;
+ 
+ 	ARGV_node = spc_var("ARGV", Nnull_string);
+ 	aptr = assoc_lookup(ARGV_node, tmp_number(0.0));
+ 	*aptr = make_string(argv0, strlen(argv0));
+ 	for (i = argc0, j = 1; i < argc; i++) {
+ 		aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j));
+ 		*aptr = make_string(argv[i], strlen(argv[i]));
+ 		j++;
+ 	}
+ 	ARGC_node = spc_var("ARGC", make_number((AWKNUM) j));
+ }
+ 
+ /*
+  * Set all the special variables to their initial values.
+  */
+ static void
+ init_vars()
+ {
+ 	extern char **environ;
+ 	char *var, *val;
+ 	NODE **aptr;
+ 	int i;
+ 
+ 	FS_node = spc_var("FS", make_string(" ", 1));
+ 	NF_node = spc_var("NF", make_number(-1.0));
+ 	RS_node = spc_var("RS", make_string("\n", 1));
+ 	NR_node = spc_var("NR", make_number(0.0));
+ 	FNR_node = spc_var("FNR", make_number(0.0));
+ 	FILENAME_node = spc_var("FILENAME", make_string("-", 1));
+ 	OFS_node = spc_var("OFS", make_string(" ", 1));
+ 	ORS_node = spc_var("ORS", make_string("\n", 1));
+ 	OFMT_node = spc_var("OFMT", make_string("%.6g", 4));
+ 	RLENGTH_node = spc_var("RLENGTH", make_number(0.0));
+ 	RSTART_node = spc_var("RSTART", make_number(0.0));
+ 	SUBSEP_node = spc_var("SUBSEP", make_string("\034", 1));
+ 	IGNORECASE_node = spc_var("IGNORECASE", make_number(0.0));
+ 
+ 	ENVIRON_node = spc_var("ENVIRON", Nnull_string);
+ 	for (i = 0; environ[i]; i++) {
+ 		static char nullstr[] = "";
+ 
+ 		var = environ[i];
+ 		val = strchr(var, '=');
+ 		if (val)
+ 			*val++ = '\0';
+ 		else
+ 			val = nullstr;
+ 		aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen (var)));
+ 		*aptr = make_string(val, strlen (val));
+ 
+ 		/* restore '=' so that system() gets a valid environment */
+ 		if (val != nullstr)
+ 			*--val = '=';
+ 	}
+ }
+ 
+ /* Create a special variable */
+ static NODE *
+ spc_var(name, value)
+ char *name;
+ NODE *value;
+ {
+ 	register NODE *r;
+ 
+ 	if ((r = lookup(variables, name)) == NULL)
+ 		r = install(variables, name, node(value, Node_var, (NODE *) NULL));
+ 	return r;
+ }
+ 
+ static void
+ pre_assign(v)
+ char *v;
+ {
+ 	char *cp;
+ 
+ 	cp = strchr(v, '=');
+ 	if (cp != NULL) {
+ 		*cp++ = '\0';
+ 		variable(v)->var_value = make_string(cp, strlen(cp));
+ 	} else {
+ 		fprintf (stderr,
+ 			"%s: '%s' argument to -v not in 'var=value' form\n",
+ 				myname, v);
+ 		usage();
+ 	}
+ }
+ 
+ SIGTYPE
+ catchsig(sig, code)
+ int sig, code;
+ {
+ #ifdef lint
+ 	code = 0; sig = code; code = sig;
+ #endif
+ 	if (sig == SIGFPE) {
+ 		fatal("floating point exception");
+ 	} else if (sig == SIGSEGV) {
+ 		msg("fatal error: segmentation fault");
+ 		/* fatal won't abort() if not compiled for debugging */
+ 		abort();
+ 	} else
+ 		cant_happen();
+ 	/* NOTREACHED */
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/missing.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/missing.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/missing.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,60 ----
+ #ifdef MSDOS
+ #define BCOPY_MISSING
+ #define STRCASE_MISSING
+ #define BLKSIZE_MISSING
+ #define SPRINTF_INT
+ #define RANDOM_MISSING
+ #define GETOPT_MISSING
+ #endif
+ 
+ #ifdef DUP2_MISSING
+ #include "missing.d/dup2.c"
+ #endif /* DUP2_MISSING */
+ 
+ #ifdef GCVT_MISSING
+ #include "missing.d/gcvt.c"
+ #endif /* GCVT_MISSING */
+ 
+ #ifdef GETOPT_MISSING
+ #include "missing.d/getopt.c"
+ #endif	/* GETOPT_MISSING */
+ 
+ #ifdef MEMCMP_MISSING
+ #include "missing.d/memcmp.c"
+ #endif	/* MEMCMP_MISSING */
+ 
+ #ifdef MEMCPY_MISSING
+ #include "missing.d/memcpy.c"
+ #endif	/* MEMCPY_MISSING */
+ 
+ #ifdef MEMSET_MISSING
+ #include "missing.d/memset.c"
+ #endif	/* MEMSET_MISSING */
+ 
+ #ifdef RANDOM_MISSING
+ #include "missing.d/random.c"
+ #endif	/* RANDOM_MISSING */
+ 
+ #ifdef STRCASE_MISSING
+ #include "missing.d/strcase.c"
+ #endif	/* STRCASE_MISSING */
+ 
+ #ifdef STRCHR_MISSING
+ #include "missing.d/strchr.c"
+ #endif	/* STRCHR_MISSING */
+ 
+ #ifdef STRERROR_MISSING
+ #include "missing.d/strerror.c"
+ #endif	/* STRERROR_MISSING */
+ 
+ #ifdef STRTOD_MISSING
+ #include "missing.d/strtod.c"
+ #endif	/* STRTOD_MISSING */
+ 
+ #ifdef TMPNAM_MISSING
+ #include "missing.d/tmpnam.c"
+ #endif	/* TMPNAM_MISSING */
+ 
+ #if defined(VPRINTF_MISSING) && defined(BSDSTDIO)
+ #include "missing.d/vprintf.c"
+ #endif	/* VPRINTF_MISSING && BSDSTDIO */


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/msg.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/msg.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/msg.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,101 ----
+ /*
+  * msg.c - routines for error messages
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ int sourceline = 0;
+ char *source = NULL;
+ 
+ /* VARARGS2 */
+ static void
+ err(s, msg, argp)
+ char *s;
+ char *msg;
+ va_list *argp;
+ {
+ 	int line;
+ 	char *file;
+ 
+ 	(void) fprintf(stderr, "%s: %s ", myname, s);
+ 	vfprintf(stderr, msg, *argp);
+ 	(void) fprintf(stderr, "\n");
+ 	line = (int) FNR_node->var_value->numbr;
+ 	if (line) {
+ 		(void) fprintf(stderr, " input line number %d", line);
+ 		file = FILENAME_node->var_value->stptr;
+ 		if (file && !STREQ(file, "-"))
+ 			(void) fprintf(stderr, ", file `%s'", file);
+ 		(void) fprintf(stderr, "\n");
+ 	}
+ 	if (sourceline) {
+ 		(void) fprintf(stderr, " source line number %d", sourceline);
+ 		if (source)
+ 			(void) fprintf(stderr, ", file `%s'", source);
+ 		(void) fprintf(stderr, "\n");
+ 	}
+ }
+ 
+ /*VARARGS0*/
+ void
+ msg(char * errmsg, ...)
+ {
+ 	va_list args;
+ 	char *mesg;
+ 
+ 	va_start(args, errmsg);
+ 	mesg = va_arg(args, char *);
+ 	err("", mesg, &args);
+ 	va_end(args);
+ }
+ 
+ /*VARARGS0*/
+ void
+ warning(char * errmsg, ...)
+ {
+ 	va_list args;
+ 	char *mesg;
+ 
+ 	va_start(args, errmsg);
+ 	mesg = va_arg(args, char *);
+ 	err("warning:", mesg, &args);
+ 	va_end(args);
+ }
+ 
+ /*VARARGS0*/
+ void
+ fatal(char * errmsg, ...)
+ {
+ 	va_list args;
+ 	char *mesg;
+ 
+ 	va_start(args, errmsg);
+ 	mesg = va_arg(args, char *);
+ 	err("fatal error:", mesg, &args);
+ 	va_end(args);
+ #ifdef DEBUG
+ 	abort();
+ #endif
+ 	exit(1);
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/node.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/node.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/node.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,344 ----
+ /*
+  * node.c -- routines for node management
+  */
+ 
+ /* 
+  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+  * 
+  * This file is part of GAWK, the GNU implementation of the
+  * AWK Progamming Language.
+  * 
+  * GAWK is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 1, or (at your option)
+  * any later version.
+  * 
+  * GAWK is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with GAWK; see the file COPYING.  If not, write to
+  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ 
+ #include "gawk.h"
+ 
+ extern double strtod();
+ 
+ /*
+  * We can't dereference a variable until after we've given it its new value.
+  * This variable points to the value we have to free up 
+  */
+ NODE *deref;
+ 
+ AWKNUM
+ r_force_number(n)
+ NODE *n;
+ {
+ 	char *ptr;
+ 
+ #ifdef DEBUG
+ 	if (n == NULL)
+ 		cant_happen();
+ 	if (n->type != Node_val)
+ 		cant_happen();
+ 	if(n->flags == 0)
+ 		cant_happen();
+ 	if (n->flags & NUM)
+ 		return n->numbr;
+ #endif
+ 	if (n->stlen == 0)
+ 		n->numbr = 0.0;
+ 	else if (n->stlen == 1) {
+ 		if (isdigit(n->stptr[0])) {
+ 			n->numbr = n->stptr[0] - '0';
+ 			n->flags |= NUMERIC;
+ 		} else
+ 			n->numbr = 0.0;
+ 	} else {
+ 		errno = 0;
+ 		n->numbr = (AWKNUM) strtod(n->stptr, &ptr);
+ 		/* the following >= should be ==, but for SunOS 3.5 strtod() */
+ 		if (errno == 0 && ptr >= n->stptr + n->stlen)
+ 			n->flags |= NUMERIC;
+ 	}
+ 	n->flags |= NUM;
+ 	return n->numbr;
+ }
+ 
+ /*
+  * the following lookup table is used as an optimization in force_string
+  * (more complicated) variations on this theme didn't seem to pay off, but 
+  * systematic testing might be in order at some point
+  */
+ static char *values[] = {
+ 	"0",
+ 	"1",
+ 	"2",
+ 	"3",
+ 	"4",
+ 	"5",
+ 	"6",
+ 	"7",
+ 	"8",
+ 	"9",
+ };
+ #define	NVAL	(sizeof(values)/sizeof(values[0]))
+ 
+ NODE *
+ r_force_string(s)
+ NODE *s;
+ {
+ 	char buf[128];
+ 	char *fmt;
+ 	long num;
+ 	char *sp = buf;
+ 
+ #ifdef DEBUG
+ 	if (s == NULL)
+ 		cant_happen();
+ 	if (s->type != Node_val)
+ 		cant_happen();
+ 	if (s->flags & STR)
+ 		return s;
+ 	if (!(s->flags & NUM))
+ 		cant_happen();
+ 	if (s->stref != 0)
+ 		cant_happen();
+ #endif
+ 	s->flags |= STR;
+ 	/* should check validity of user supplied OFMT */
+ 	fmt = OFMT_node->var_value->stptr;
+ 	if ((num = s->numbr) == s->numbr) {
+ 		/* integral value */
+ 		if (num < NVAL && num >= 0) {
+ 			sp = values[num];
+ 			s->stlen = 1;
+ 		} else {
+ 			(void) sprintf(sp, "%ld", num);
+ 			s->stlen = strlen(sp);
+ 		}
+ 	} else {
+ 		(void) sprintf(sp, fmt, s->numbr);
+ 		s->stlen = strlen(sp);
+ 	}
+ 	s->stref = 1;
+ 	emalloc(s->stptr, char *, s->stlen + 1, "force_string");
+ 	memcpy(s->stptr, sp, s->stlen+1);
+ 	return s;
+ }
+ 
+ /*
+  * Duplicate a node.  (For strings, "duplicate" means crank up the
+  * reference count.)
+  */
+ NODE *
+ dupnode(n)
+ NODE *n;
+ {
+ 	register NODE *r;
+ 
+ 	if (n->flags & TEMP) {
+ 		n->flags &= ~TEMP;
+ 		n->flags |= MALLOC;
+ 		return n;
+ 	}
+ 	if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
+ 		if (n->stref < 255)
+ 			n->stref++;
+ 		return n;
+ 	}
+ 	r = newnode(Node_illegal);
+ 	*r = *n;
+ 	r->flags &= ~(PERM|TEMP);
+ 	r->flags |= MALLOC;
+ 	if (n->type == Node_val && (n->flags & STR)) {
+ 		r->stref = 1;
+ 		emalloc(r->stptr, char *, r->stlen + 1, "dupnode");
+ 		memcpy(r->stptr, n->stptr, r->stlen+1);
+ 	}
+ 	return r;
+ }
+ 
+ /* this allocates a node with defined numbr */
+ NODE *
+ make_number(x)
+ AWKNUM x;
+ {
+ 	register NODE *r;
+ 
+ 	r = newnode(Node_val);
+ 	r->numbr = x;
+ 	r->flags |= (NUM|NUMERIC);
+ 	r->stref = 0;
+ 	return r;
+ }
+ 
+ /*
+  * This creates temporary nodes.  They go away quite quickly, so don't use
+  * them for anything important 
+  */
+ NODE *
+ tmp_number(x)
+ AWKNUM x;
+ {
+ 	NODE *r;
+ 
+ 	r = make_number(x);
+ 	r->flags |= TEMP;
+ 	return r;
+ }
+ 
+ /*
+  * Make a string node.
+  */
+ 
+ NODE *
+ make_str_node(s, len, scan)
+ char *s;
+ int len;
+ int scan;
+ {
+ 	register NODE *r;
+ 	char *pf;
+ 	register char *pt;
+ 	register int c;
+ 	register char *end;
+ 
+ 	r = newnode(Node_val);
+ 	emalloc(r->stptr, char *, len + 1, s);
+ 	memcpy(r->stptr, s, len);
+ 	r->stptr[len] = '\0';
+ 	end = &(r->stptr[len]);
+ 	       
+ 	if (scan) {	/* scan for escape sequences */
+ 		for (pf = pt = r->stptr; pf < end;) {
+ 			c = *pf++;
+ 			if (c == '\\') {
+ 				c = parse_escape(&pf);
+ 				if (c < 0)
+ 					cant_happen();
+ 				*pt++ = c;
+ 			} else
+ 				*pt++ = c;
+ 		}
+ 		len = pt - r->stptr;
+ 		erealloc(r->stptr, char *, len + 1, "make_str_node");
+ 		r->stptr[len] = '\0';
+ 		r->flags |= PERM;
+ 	}
+ 	r->stlen = len;
+ 	r->stref = 1;
+ 	r->flags |= (STR|MALLOC);
+ 
+ 	return r;
+ }
+ 
+ /* Read the warning under tmp_number */
+ NODE *
+ tmp_string(s, len)
+ char *s;
+ int len;
+ {
+ 	register NODE *r;
+ 
+ 	r = make_string(s, len);
+ 	r->flags |= TEMP;
+ 	return r;
+ }
+ 
+ 
+ #define NODECHUNK	100
+ 
+ static NODE *nextfree = NULL;
+ 
+ NODE *
+ newnode(ty)
+ NODETYPE ty;
+ {
+ 	NODE *it;
+ 	NODE *np;
+ 
+ #if defined(MPROF) || defined(NOMEMOPT)
+ 	emalloc(it, NODE *, sizeof(NODE), "newnode");
+ #else
+ 	if (nextfree == NULL) {
+ 		/* get more nodes and initialize list */
+ 		emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
+ 		for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
+ 			np->nextp = np + 1;
+ 		np->nextp = NULL;
+ 	}
+ 	/* get head of freelist */
+ 	it = nextfree;
+ 	nextfree = nextfree->nextp;
+ #endif
+ 	it->type = ty;
+ 	it->flags = MALLOC;
+ #ifdef MEMDEBUG
+ 	fprintf(stderr, "node: new: %0x\n", it);
+ #endif
+ 	return it;
+ }
+ 
+ void
+ freenode(it)
+ NODE *it;
+ {
+ #ifdef DEBUG
+ 	NODE *nf;
+ #endif
+ #ifdef MEMDEBUG
+ 	fprintf(stderr, "node: free: %0x\n", it);
+ #endif
+ #if defined(MPROF) || defined(NOMEMOPT) 
+ 	free((char *) it);
+ #elif defined(IGNOREFREE)	
+ #else
+ #ifdef DEBUG
+ 	for (nf = nextfree; nf; nf = nf->nextp)
+ 		if (nf == it)
+ 			fatal("attempt to free free node");
+ #endif
+ 	/* add it to head of freelist */
+ 	it->nextp = nextfree;
+ 	nextfree = it;
+ #endif
+ }
+ 
+ #ifdef DEBUG
+ pf()
+ {
+ 	NODE *nf = nextfree;
+ 	while (nf != NULL) {
+ 		fprintf(stderr, "%0x ", nf);
+ 		nf = nf->nextp;
+ 	}
+ }
+ #endif
+ 
+ void
+ do_deref()
+ {
+ 	if (deref == NULL)
+ 		return;
+ 	if (deref->flags & PERM) {
+ 		deref = 0;
+ 		return;
+ 	}
+ 	if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
+ 		deref->flags &= ~TEMP;
+ 		if (deref->flags & STR) {
+ 			if (deref->stref > 1 && deref->stref != 255) {
+ 				deref->stref--;
+ 				deref = 0;
+ 				return;
+ 			}
+ 			free(deref->stptr);
+ 		}
+ 		freenode(deref);
+ 	}
+ 	deref = 0;
+ }


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/patchlevel.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/patchlevel.h:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/patchlevel.h	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1 ----
+ #define PATCHLEVEL	1


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/regex.c
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/regex.c:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/regex.c	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,1875 ----
+ /* Extended regular expression matching and search.
+    Copyright (C) 1985 Free Software Foundation, Inc.
+ 
+ 		       NO WARRANTY
+ 
+   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+ NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
+ WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
+ RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
+ AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
+ DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+ CORRECTION.
+ 
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+ STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
+ WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
+ OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+ USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
+ DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
+ A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
+ PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
+ 
+ 		GENERAL PUBLIC LICENSE TO COPY
+ 
+   1. You may copy and distribute verbatim copies of this source file
+ as you receive it, in any medium, provided that you conspicuously and
+ appropriately publish on each copy a valid copyright notice "Copyright
+ (C) 1985 Free Software Foundation, Inc."; and include following the
+ copyright notice a verbatim copy of the above disclaimer of warranty
+ and of this License.  You may charge a distribution fee for the
+ physical act of transferring a copy.
+ 
+   2. You may modify your copy or copies of this source file or
+ any portion of it, and copy and distribute such modifications under
+ the terms of Paragraph 1 above, provided that you also do the following:
+ 
+     a) cause the modified files to carry prominent notices stating
+     that you changed the files and the date of any change; and
+ 
+     b) cause the whole of any work that you distribute or publish,
+     that in whole or in part contains or is a derivative of this
+     program or any part thereof, to be licensed at no charge to all
+     third parties on terms identical to those contained in this
+     License Agreement (except that you may choose to grant more extensive
+     warranty protection to some or all third parties, at your option).
+ 
+     c) You may charge a distribution fee for the physical act of
+     transferring a copy, and you may at your option offer warranty
+     protection in exchange for a fee.
+ 
+ Mere aggregation of another unrelated program with this program (or its
+ derivative) on a volume of a storage or distribution medium does not bring
+ the other program under the scope of these terms.
+ 
+   3. You may copy and distribute this program (or a portion or derivative
+ of it, under Paragraph 2) in object code or executable form under the terms
+ of Paragraphs 1 and 2 above provided that you also do one of the following:
+ 
+     a) accompany it with the complete corresponding machine-readable
+     source code, which must be distributed under the terms of
+     Paragraphs 1 and 2 above; or,
+ 
+     b) accompany it with a written offer, valid for at least three
+     years, to give any third party free (except for a nominal
+     shipping charge) a complete machine-readable copy of the
+     corresponding source code, to be distributed under the terms of
+     Paragraphs 1 and 2 above; or,
+ 
+     c) accompany it with the information you received as to where the
+     corresponding source code may be obtained.  (This alternative is
+     allowed only for noncommercial distribution and only if you
+     received the program in object code or executable form alone.)
+ 
+ For an executable file, complete source code means all the source code for
+ all modules it contains; but, as a special exception, it need not include
+ source code for modules which are standard libraries that accompany the
+ operating system on which the executable file runs.
+ 
+   4. You may not copy, sublicense, distribute or transfer this program
+ except as expressly provided under this License Agreement.  Any attempt
+ otherwise to copy, sublicense, distribute or transfer this program is void and
+ your rights to use the program under this License agreement shall be
+ automatically terminated.  However, parties who have received computer
+ software programs from you with this License Agreement will not have
+ their licenses terminated so long as such parties remain in full compliance.
+ 
+   5. If you wish to incorporate parts of this program into other free
+ programs whose distribution conditions are different, write to the Free
+ Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
+ worked out a simple rule that can be stated here, but we will often permit
+ this.  We will be guided by the two goals of preserving the free status of
+ all derivatives of our free software and of promoting the sharing and reuse of
+ software.
+ 
+ 
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them.   Help stamp out software-hoarding!  */
+ 
+ #ifdef MSDOS
+ #include <malloc.h>
+ static  void init_syntax_once(void );
+ extern  int re_set_syntax(int syntax);
+ extern  char *re_compile_pattern(char *pattern,int size,struct re_pattern_buffer *bufp);
+ static  int store_jump(char *from,char opcode,char *to);
+ static  int insert_jump(char op,char *from,char *to,char *current_end);
+ extern  void re_compile_fastmap(struct re_pattern_buffer *bufp);
+ extern  int re_search(struct re_pattern_buffer *pbufp,char *string,int size,int startpos,int range,struct re_registers *regs);
+ extern  int re_search_2(struct re_pattern_buffer *pbufp,char *string1,int size1,char *string2,int size2,int startpos,int range,struct re_registers *regs,int mstop);
+ extern  int re_match(struct re_pattern_buffer *pbufp,char *string,int size,int pos,struct re_registers *regs);
+ extern  int re_match_2(struct re_pattern_buffer *pbufp,unsigned char *string1,int size1,unsigned char *string2,int size2,int pos,struct re_registers *regs,int mstop);
+ static  int bcmp_translate(unsigned char *s1,unsigned char *s2,int len,unsigned char *translate);
+ extern  char *re_comp(char *s);
+ extern  int re_exec(char *s);
+ #endif
+ 
+ #ifdef BWGC
+ #define realloc(ptr, size)	gc_realloc(ptr, size)
+ #endif
+ 
+ /* To test, compile with -Dtest.
+  This Dtestable feature turns this into a self-contained program
+  which reads a pattern, describes how it compiles,
+  then reads a string and searches for it.  */
+ 
+ #ifdef emacs
+ 
+ /* The `emacs' switch turns on certain special matching commands
+  that make sense only in emacs. */
+ 
+ #include "config.h"
+ #include "lisp.h"
+ #include "buffer.h"
+ #include "syntax.h"
+ 
+ #else  /* not emacs */
+ 
+ #ifdef BCOPY_MISSING
+ #define bcopy(s,d,n)	memcpy((d),(s),(n))
+ #define bcmp(s1,s2,n)	memcmp((s1),(s2),(n))
+ #define bzero(s,n)	memset((s),0,(n))
+ #else
+ void bcopy();
+ int bcmp();
+ void bzero();
+ #endif
+ 
+ /* Make alloca work the best possible way.  */
+ #ifdef __GNUC__
+ #define alloca __builtin_alloca
+ #else
+ #ifdef sparc
+ #include <alloca.h>
+ #endif
+ #endif
+ 
+ /*
+  * Define the syntax stuff, so we can do the \<...\> things.
+  */
+ 
+ #ifndef Sword /* must be non-zero in some of the tests below... */
+ #define Sword 1
+ #endif
+ 
+ #define SYNTAX(c) re_syntax_table[c]
+ 
+ #ifdef SYNTAX_TABLE
+ 
+ char *re_syntax_table;
+ 
+ #else
+ 
+ static char re_syntax_table[256];
+ 
+ static void
+ init_syntax_once ()
+ {
+    register int c;
+    static int done = 0;
+ 
+    if (done)
+      return;
+ 
+    bzero (re_syntax_table, sizeof re_syntax_table);
+ 
+    for (c = 'a'; c <= 'z'; c++)
+      re_syntax_table[c] = Sword;
+ 
+    for (c = 'A'; c <= 'Z'; c++)
+      re_syntax_table[c] = Sword;
+ 
+    for (c = '0'; c <= '9'; c++)
+      re_syntax_table[c] = Sword;
+ 
+    done = 1;
+ }
+ 
+ #endif /* SYNTAX_TABLE */
+ #endif /* not emacs */
+ 
+ #include "regex.h"
+ 
+ /* Number of failure points to allocate space for initially,
+  when matching.  If this number is exceeded, more space is allocated,
+  so it is not a hard limit.  */
+ 
+ #ifndef NFAILURES
+ #define NFAILURES 80
+ #endif /* NFAILURES */
+ 
+ /* width of a byte in bits */
+ 
+ #define BYTEWIDTH 8
+ 
+ #ifndef SIGN_EXTEND_CHAR
+ #define SIGN_EXTEND_CHAR(x) (x)
+ #endif
+ 
+ static int obscure_syntax = 0;
+ 
+ /* Specify the precise syntax of regexp for compilation.
+    This provides for compatibility for various utilities
+    which historically have different, incompatible syntaxes.
+ 
+    The argument SYNTAX is a bit-mask containing the two bits
+    RE_NO_BK_PARENS and RE_NO_BK_VBAR.  */
+ 
+ int
+ re_set_syntax (syntax)
+ {
+   int ret;
+ 
+   ret = obscure_syntax;
+   obscure_syntax = syntax;
+   return ret;
+ }
+ 
+ /* re_compile_pattern takes a regular-expression string
+    and converts it into a buffer full of byte commands for matching.
+ 
+   PATTERN   is the address of the pattern string
+   SIZE      is the length of it.
+   BUFP	    is a  struct re_pattern_buffer *  which points to the info
+ 	    on where to store the byte commands.
+ 	    This structure contains a  char *  which points to the
+ 	    actual space, which should have been obtained with malloc.
+ 	    re_compile_pattern may use  realloc  to grow the buffer space.
+ 
+   The number of bytes of commands can be found out by looking in
+   the  struct re_pattern_buffer  that bufp pointed to,
+   after re_compile_pattern returns.
+ */
+ 
+ #define PATPUSH(ch) (*b++ = (char) (ch))
+ 
+ #define PATFETCH(c) \
+  {if (p == pend) goto end_of_pattern; \
+   c = * (unsigned char *) p++; \
+   if (translate) c = translate[c]; }
+ 
+ #define PATFETCH_RAW(c) \
+  {if (p == pend) goto end_of_pattern; \
+   c = * (unsigned char *) p++; }
+ 
+ #define PATUNFETCH p--
+ 
+ #ifdef MSDOS
+ #define MaxAllocation (1<<14)
+ #else
+ #define MaxAllocation (1<<16)
+ #endif
+ #define EXTEND_BUFFER \
+   { char *old_buffer = bufp->buffer; \
+     if (bufp->allocated == MaxAllocation) goto too_big; \
+     bufp->allocated *= 2; \
+     if (bufp->allocated > MaxAllocation) bufp->allocated = MaxAllocation; \
+     if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
+       goto memory_exhausted; \
+     c = bufp->buffer - old_buffer; \
+     b += c; \
+     if (fixup_jump) \
+       fixup_jump += c; \
+     if (laststart) \
+       laststart += c; \
+     begalt += c; \
+     if (pending_exact) \
+       pending_exact += c; \
+   }
+ 
+ #ifdef NEVER
+ #define EXTEND_BUFFER \
+   { unsigned b_off = b - bufp->buffer, \
+ 			 f_off, l_off, p_off, \
+    			 beg_off = begalt - bufp->buffer; \
+     if (fixup_jump) \
+ 	   f_off = fixup_jump - bufp->buffer; \
+     if (laststart) \
+ 	   l_off = laststart - bufp->buffer; \
+     if (pending_exact) \
+ 	   p_off = pending_exact - bufp->buffer; \
+     if (bufp->allocated == MaxAllocation) goto too_big; \
+     bufp->allocated *= 2; \
+     if (bufp->allocated > MaxAllocation) bufp->allocated = MaxAllocation; \
+     if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
+       goto memory_exhausted; \
+ 	b = bufp->buffer + b_off; \
+     if (fixup_jump) \
+       fixup_jump = bufp->buffer + f_off; \
+     if (laststart) \
+       laststart = bufp->buffer + l_off; \
+     begalt = bufp->buffer + beg_off; \
+     if (pending_exact) \
+       pending_exact = bufp->buffer + p_off; \
+   }
+ #endif
+ static int store_jump (), insert_jump ();
+ 
+ char *
+ re_compile_pattern (pattern, size, bufp)
+      char *pattern;
+      int size;
+      struct re_pattern_buffer *bufp;
+ {
+   register char *b = bufp->buffer;
+   register char *p = pattern;
+   char *pend = pattern + size;
+   register unsigned c, c1;
+   char *p1;
+   unsigned char *translate = (unsigned char *) bufp->translate;
+ 
+   /* address of the count-byte of the most recently inserted "exactn" command.
+     This makes it possible to tell whether a new exact-match character
+     can be added to that command or requires a new "exactn" command. */
+      
+   char *pending_exact = 0;
+ 
+   /* address of the place where a forward-jump should go
+     to the end of the containing expression.
+     Each alternative of an "or", except the last, ends with a forward-jump
+     of this sort. */
+ 
+   char *fixup_jump = 0;
+ 
+   /* address of start of the most recently finished expression.
+     This tells postfix * where to find the start of its operand. */
+ 
+   char *laststart = 0;
+ 
+   /* In processing a repeat, 1 means zero matches is allowed */
+ 
+   char zero_times_ok;
+ 
+   /* In processing a repeat, 1 means many matches is allowed */
+ 
+   char many_times_ok;
+ 
+   /* address of beginning of regexp, or inside of last \( */
+ 
+   char *begalt = b;
+ 
+   /* Stack of information saved by \( and restored by \).
+      Four stack elements are pushed by each \(:
+        First, the value of b.
+        Second, the value of fixup_jump.
+        Third, the value of regnum.
+        Fourth, the value of begalt.  */
+ 
+   int stackb[40];
+   int *stackp = stackb;
+   int *stacke = stackb + 40;
+   int *stackt;
+ 
+   /* Counts \('s as they are encountered.  Remembered for the matching \),
+      where it becomes the "register number" to put in the stop_memory command */
+ 
+   int regnum = 1;
+ 
+   bufp->fastmap_accurate = 0;
+ 
+ #ifndef emacs
+ #ifndef SYNTAX_TABLE
+   /*
+    * Initialize the syntax table.
+    */
+    init_syntax_once();
+ #endif
+ #endif
+ 
+   if (bufp->allocated == 0)
+     {
+       bufp->allocated = 28;
+       if (bufp->buffer)
+ 	/* EXTEND_BUFFER loses when bufp->allocated is 0 */
+ 	bufp->buffer = (char *) realloc (bufp->buffer, 28);
+       else
+ 	/* Caller did not allocate a buffer.  Do it for him */
+ 	bufp->buffer = (char *) malloc (28);
+       if (!bufp->buffer) goto memory_exhausted;
+       begalt = b = bufp->buffer;
+     }
+ 
+   while (p != pend)
+     {
+       if (b - bufp->buffer > bufp->allocated - 10)
+ 	/* Note that EXTEND_BUFFER clobbers c */
+ 	EXTEND_BUFFER;
+ 
+       PATFETCH (c);
+ 
+       switch (c)
+ 	{
+ 	case '$':
+ 	  if (obscure_syntax & RE_TIGHT_VBAR)
+ 	    {
+ 	      if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
+ 		goto normal_char;
+ 	      /* Make operand of last vbar end before this `$'.  */
+ 	      if (fixup_jump)
+ 		store_jump (fixup_jump, jump, b);
+ 	      fixup_jump = 0;
+ 	      PATPUSH (endline);
+ 	      break;
+ 	    }
+ 
+ 	  /* $ means succeed if at end of line, but only in special contexts.
+ 	    If randomly in the middle of a pattern, it is a normal character. */
+ 	  if (p == pend || *p == '\n'
+ 	      || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
+ 	      || (obscure_syntax & RE_NO_BK_PARENS
+ 		  ? *p == ')'
+ 		  : *p == '\\' && p[1] == ')')
+ 	      || (obscure_syntax & RE_NO_BK_VBAR
+ 		  ? *p == '|'
+ 		  : *p == '\\' && p[1] == '|'))
+ 	    {
+ 	      PATPUSH (endline);
+ 	      break;
+ 	    }
+ 	  goto normal_char;
+ 
+ 	case '^':
+ 	  /* ^ means succeed if at beg of line, but only if no preceding pattern. */
+ 
+ 	  if (laststart && p[-2] != '\n'
+ 	      && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ 	    goto normal_char;
+ 	  if (obscure_syntax & RE_TIGHT_VBAR)
+ 	    {
+ 	      if (p != pattern + 1
+ 		  && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ 		goto normal_char;
+ 	      PATPUSH (begline);
+ 	      begalt = b;
+ 	    }
+ 	  else
+ 	    PATPUSH (begline);
+ 	  break;
+ 
+ 	case '+':
+ 	case '?':
+ 	  if (obscure_syntax & RE_BK_PLUS_QM)
+ 	    goto normal_char;
+ 	handle_plus:
+ 	case '*':
+ 	  /* If there is no previous pattern, char not special. */
+ 	  if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ 	    goto normal_char;
+ 	  /* If there is a sequence of repetition chars,
+ 	     collapse it down to equivalent to just one.  */
+ 	  zero_times_ok = 0;
+ 	  many_times_ok = 0;
+ 	  while (1)
+ 	    {
+ 	      zero_times_ok |= c != '+';
+ 	      many_times_ok |= c != '?';
+ 	      if (p == pend)
+ 		break;
+ 	      PATFETCH (c);
+ 	      if (c == '*')
+ 		;
+ 	      else if (!(obscure_syntax & RE_BK_PLUS_QM)
+ 		       && (c == '+' || c == '?'))
+ 		;
+ 	      else if ((obscure_syntax & RE_BK_PLUS_QM)
+ 		       && c == '\\')
+ 		{
+ 		  int c1;
+ 		  PATFETCH (c1);
+ 		  if (!(c1 == '+' || c1 == '?'))
+ 		    {
+ 		      PATUNFETCH;
+ 		      PATUNFETCH;
+ 		      break;
+ 		    }
+ 		  c = c1;
+ 		}
+ 	      else
+ 		{
+ 		  PATUNFETCH;
+ 		  break;
+ 		}
+ 	    }
+ 
+ 	  /* Star, etc. applied to an empty pattern is equivalent
+ 	     to an empty pattern.  */
+ 	  if (!laststart)
+ 	    break;
+ 
+ 	  /* Now we know whether 0 matches is allowed,
+ 	     and whether 2 or more matches is allowed.  */
+ 	  if (many_times_ok)
+ 	    {
+ 	      /* If more than one repetition is allowed,
+ 		 put in a backward jump at the end.  */
+ 	      store_jump (b, maybe_finalize_jump, laststart - 3);
+ 	      b += 3;
+ 	    }
+ 	  insert_jump (on_failure_jump, laststart, b + 3, b);
+ 	  pending_exact = 0;
+ 	  b += 3;
+ 	  if (!zero_times_ok)
+ 	    {
+ 	      /* At least one repetition required: insert before the loop
+ 		 a skip over the initial on-failure-jump instruction */
+ 	      insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
+ 	      b += 3;
+ 	    }
+ 	  break;
+ 
+ 	case '.':
+ 	  laststart = b;
+ 	  PATPUSH (anychar);
+ 	  break;
+ 
+ 	case '[':
+ 	  while (b - bufp->buffer
+ 		 > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
+ 	    /* Note that EXTEND_BUFFER clobbers c */
+ 	    EXTEND_BUFFER;
+ 
+ 	  laststart = b;
+ 	  if (*p == '^')
+ 	    PATPUSH (charset_not), p++;
+ 	  else
+ 	    PATPUSH (charset);
+ 	  p1 = p;
+ 
+ 	  PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+ 	  /* Clear the whole map */
+ 	  bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+ 	  /* Read in characters and ranges, setting map bits */
+ 	  while (1)
+ 	    {
+ 	      PATFETCH (c);
+ 
+ 	      /* If awk, \ escapes characters inside [...].  */
+ 	      if ((obscure_syntax & RE_AWK_CLASS_HACK) && c == '\\')
+ 	        {
+ 	          PATFETCH(c1);
+ 	          b[c1 / BYTEWIDTH] |= 1 << (c1 % BYTEWIDTH);
+ 	          continue;
+ 	        }
+ 
+ 	      if (c == ']' && p != p1 + 1) break;
+ 	      if (*p == '-' && p[1] != ']')
+ 		{
+ 		  PATFETCH (c1);
+ 		  PATFETCH (c1);
+ 		  while (c <= c1)
+ 		    b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++;
+ 		}
+ 	      else
+ 		{
+ 		  b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH);
+ 		}
+ 	    }
+ 	  /* Discard any bitmap bytes that are all 0 at the end of the map.
+ 	     Decrement the map-length byte too. */
+ 	  while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ 	    b[-1]--;
+ 	  b += b[-1];
+ 	  break;
+ 
+ 	case '(':
+ 	  if (! (obscure_syntax & RE_NO_BK_PARENS))
+ 	    goto normal_char;
+ 	  else
+ 	    goto handle_open;
+ 
+ 	case ')':
+ 	  if (! (obscure_syntax & RE_NO_BK_PARENS))
+ 	    goto normal_char;
+ 	  else
+ 	    goto handle_close;
+ 
+ 	case '\n':
+ 	  if (! (obscure_syntax & RE_NEWLINE_OR))
+ 	    goto normal_char;
+ 	  else
+ 	    goto handle_bar;
+ 
+ 	case '|':
+ 	  if (! (obscure_syntax & RE_NO_BK_VBAR))
+ 	    goto normal_char;
+ 	  else
+ 	    goto handle_bar;
+ 
+         case '\\':
+ 	  if (p == pend) goto invalid_pattern;
+ 	  PATFETCH_RAW (c);
+ 	  switch (c)
+ 	    {
+ 	    case '(':
+ 	      if (obscure_syntax & RE_NO_BK_PARENS)
+ 		goto normal_backsl;
+ 	    handle_open:
+ 	      if (stackp == stacke) goto nesting_too_deep;
+ 	      if (regnum < RE_NREGS)
+ 	        {
+ 		  PATPUSH (start_memory);
+ 		  PATPUSH (regnum);
+ 	        }
+ 	      *stackp++ = b - bufp->buffer;
+ 	      *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0;
+ 	      *stackp++ = regnum++;
+ 	      *stackp++ = begalt - bufp->buffer;
+ 	      fixup_jump = 0;
+ 	      laststart = 0;
+ 	      begalt = b;
+ 	      break;
+ 
+ 	    case ')':
+ 	      if (obscure_syntax & RE_NO_BK_PARENS)
+ 		goto normal_backsl;
+ 	    handle_close:
+ 	      if (stackp == stackb) goto unmatched_close;
+ 	      begalt = *--stackp + bufp->buffer;
+ 	      if (fixup_jump)
+ 		store_jump (fixup_jump, jump, b);
+ 	      if (stackp[-1] < RE_NREGS)
+ 		{
+ 		  PATPUSH (stop_memory);
+ 		  PATPUSH (stackp[-1]);
+ 		}
+ 	      stackp -= 2;
+ 	      fixup_jump = 0;
+ 	      if (*stackp)
+ 		fixup_jump = *stackp + bufp->buffer - 1;
+ 	      laststart = *--stackp + bufp->buffer;
+ 	      break;
+ 
+ 	    case '|':
+ 	      if (obscure_syntax & RE_NO_BK_VBAR)
+ 		goto normal_backsl;
+ 	    handle_bar:
+ 	      insert_jump (on_failure_jump, begalt, b + 6, b);
+ 	      pending_exact = 0;
+ 	      b += 3;
+ 	      if (fixup_jump)
+ 		store_jump (fixup_jump, jump, b);
+ 	      fixup_jump = b;
+ 	      b += 3;
+ 	      laststart = 0;
+ 	      begalt = b;
+ 	      break;
+ 
+ #ifdef emacs
+ 	    case '=':
+ 	      PATPUSH (at_dot);
+ 	      break;
+ 
+ 	    case 's':	
+ 	      laststart = b;
+ 	      PATPUSH (syntaxspec);
+ 	      PATFETCH (c);
+ 	      PATPUSH (syntax_spec_code[c]);
+ 	      break;
+ 
+ 	    case 'S':
+ 	      laststart = b;
+ 	      PATPUSH (notsyntaxspec);
+ 	      PATFETCH (c);
+ 	      PATPUSH (syntax_spec_code[c]);
+ 	      break;
+ #endif /* emacs */
+ 
+ 	    case 'w':
+ 	      laststart = b;
+ 	      PATPUSH (wordchar);
+ 	      break;
+ 
+ 	    case 'W':
+ 	      laststart = b;
+ 	      PATPUSH (notwordchar);
+ 	      break;
+ 
+ 	    case '<':
+ 	      PATPUSH (wordbeg);
+ 	      break;
+ 
+ 	    case '>':
+ 	      PATPUSH (wordend);
+ 	      break;
+ 
+ 	    case 'b':
+ 	      PATPUSH (wordbound);
+ 	      break;
+ 
+ 	    case 'B':
+ 	      PATPUSH (notwordbound);
+ 	      break;
+ 
+ 	    case '`':
+ 	      PATPUSH (begbuf);
+ 	      break;
+ 
+ 	    case '\'':
+ 	      PATPUSH (endbuf);
+ 	      break;
+ 
+ 	    case '1':
+ 	    case '2':
+ 	    case '3':
+ 	    case '4':
+ 	    case '5':
+ 	    case '6':
+ 	    case '7':
+ 	    case '8':
+ 	    case '9':
+ 	      c1 = c - '0';
+ 	      if (c1 >= regnum)
+ 		goto normal_char;
+ 	      for (stackt = stackp - 2;  stackt > stackb;  stackt -= 4)
+  		if (*stackt == c1)
+ 		  goto normal_char;
+ 	      laststart = b;
+ 	      PATPUSH (duplicate);
+ 	      PATPUSH (c1);
+ 	      break;
+ 
+ 	    case '+':
+ 	    case '?':
+ 	      if (obscure_syntax & RE_BK_PLUS_QM)
+ 		goto handle_plus;
+ 
+ 	    default:
+ 	    normal_backsl:
+ 	      /* You might think it would be useful for \ to mean
+ 		 not to translate; but if we don't translate it
+ 		 it will never match anything.  */
+ 	      if (translate) c = translate[c];
+ 	      goto normal_char;
+ 	    }
+ 	  break;
+ 
+ 	default:
+ 	normal_char:
+ 	  if (!pending_exact || pending_exact + *pending_exact + 1 != b
+ 	      || *pending_exact == 0177 || *p == '*' || *p == '^'
+ 	      || ((obscure_syntax & RE_BK_PLUS_QM)
+ 		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+ 		  : (*p == '+' || *p == '?')))
+ 	    {
+ 	      laststart = b;
+ 	      PATPUSH (exactn);
+ 	      pending_exact = b;
+ 	      PATPUSH (0);
+ 	    }
+ 	  PATPUSH (c);
+ 	  (*pending_exact)++;
+ 	}
+     }
+ 
+   if (fixup_jump)
+     store_jump (fixup_jump, jump, b);
+ 
+   if (stackp != stackb) goto unmatched_open;
+ 
+   bufp->used = b - bufp->buffer;
+   return 0;
+ 
+  invalid_pattern:
+   return "Invalid regular expression";
+ 
+  unmatched_open:
+   return "Unmatched \\(";
+ 
+  unmatched_close:
+   return "Unmatched \\)";
+ 
+  end_of_pattern:
+   return "Premature end of regular expression";
+ 
+  nesting_too_deep:
+   return "Nesting too deep";
+ 
+  too_big:
+   return "Regular expression too big";
+ 
+  memory_exhausted:
+   return "Memory exhausted";
+ }
+ 
+ /* Store where `from' points a jump operation to jump to where `to' points.
+   `opcode' is the opcode to store. */
+ 
+ static int
+ store_jump (from, opcode, to)
+      char *from, *to;
+      char opcode;
+ {
+   from[0] = opcode;
+   from[1] = (to - (from + 3)) & 0377;
+   from[2] = (to - (from + 3)) >> 8;
+ }
+ 
+ /* Open up space at char FROM, and insert there a jump to TO.
+    CURRENT_END gives te end of the storage no in use,
+    so we know how much data to copy up.
+    OP is the opcode of the jump to insert.
+ 
+    If you call this function, you must zero out pending_exact.  */
+ 
+ static int
+ insert_jump (op, from, to, current_end)
+      char op;
+      char *from, *to, *current_end;
+ {
+   register char *pto = current_end + 3;
+   register char *pfrom = current_end;
+   while (pfrom != from)
+     *--pto = *--pfrom;
+   store_jump (from, op, to);
+ }
+ 
+ /* Given a pattern, compute a fastmap from it.
+  The fastmap records which of the (1 << BYTEWIDTH) possible characters
+  can start a string that matches the pattern.
+  This fastmap is used by re_search to skip quickly over totally implausible text.
+ 
+  The caller must supply the address of a (1 << BYTEWIDTH)-byte data area
+  as bufp->fastmap.
+  The other components of bufp describe the pattern to be used.  */
+ 
+ void
+ re_compile_fastmap (bufp)
+      struct re_pattern_buffer *bufp;
+ {
+   unsigned char *pattern = (unsigned char *) bufp->buffer;
+   int size = bufp->used;
+   register char *fastmap = bufp->fastmap;
+   register unsigned char *p = pattern;
+   register unsigned char *pend = pattern + size;
+   register int j, k;
+   unsigned char *translate = (unsigned char *) bufp->translate;
+ 
+   unsigned char *stackb[NFAILURES];
+   unsigned char **stackp = stackb;
+ 
+   bzero (fastmap, (1 << BYTEWIDTH));
+   bufp->fastmap_accurate = 1;
+   bufp->can_be_null = 0;
+       
+   while (p)
+     {
+       if (p == pend)
+ 	{
+ 	  bufp->can_be_null = 1;
+ 	  break;
+ 	}
+ #ifdef SWITCH_ENUM_BUG
+       switch ((int) ((enum regexpcode) *p++))
+ #else
+       switch ((enum regexpcode) *p++)
+ #endif
+ 	{
+ 	case exactn:
+ 	  if (translate)
+ 	    fastmap[translate[p[1]]] = 1;
+ 	  else
+ 	    fastmap[p[1]] = 1;
+ 	  break;
+ 
+         case begline:
+         case before_dot:
+ 	case at_dot:
+ 	case after_dot:
+ 	case begbuf:
+ 	case endbuf:
+ 	case wordbound:
+ 	case notwordbound:
+ 	case wordbeg:
+ 	case wordend:
+ 	  continue;
+ 
+ 	case endline:
+ 	  if (translate)
+ 	    fastmap[translate['\n']] = 1;
+ 	  else
+ 	    fastmap['\n'] = 1;
+ 	  if (bufp->can_be_null != 1)
+ 	    bufp->can_be_null = 2;
+ 	  break;
+ 
+ 	case finalize_jump:
+ 	case maybe_finalize_jump:
+ 	case jump:
+ 	case dummy_failure_jump:
+ 	  bufp->can_be_null = 1;
+ 	  j = *p++ & 0377;
+ 	  j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ 	  p += j + 1;		/* The 1 compensates for missing ++ above */
+ 	  if (j > 0)
+ 	    continue;
+ 	  /* Jump backward reached implies we just went through
+ 	     the body of a loop and matched nothing.
+ 	     Opcode jumped to should be an on_failure_jump.
+ 	     Just treat it like an ordinary jump.
+ 	     For a * loop, it has pushed its failure point already;
+ 	     if so, discard that as redundant.  */
+ 	  if ((enum regexpcode) *p != on_failure_jump)
+ 	    continue;
+ 	  p++;
+ 	  j = *p++ & 0377;
+ 	  j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ 	  p += j + 1;		/* The 1 compensates for missing ++ above */
+ 	  if (stackp != stackb && *stackp == p)
+ 	    stackp--;
+ 	  continue;
+ 	  
+ 	case on_failure_jump:
+ 	  j = *p++ & 0377;
+ 	  j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ 	  p++;
+ 	  *++stackp = p + j;
+ 	  continue;
+ 
+ 	case start_memory:
+ 	case stop_memory:
+ 	  p++;
+ 	  continue;
+ 
+ 	case duplicate:
+ 	  bufp->can_be_null = 1;
+ 	  fastmap['\n'] = 1;
+ 	case anychar:
+ 	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+ 	    if (j != '\n')
+ 	      fastmap[j] = 1;
+ 	  if (bufp->can_be_null)
+ 	    return;
+ 	  /* Don't return; check the alternative paths
+ 	     so we can set can_be_null if appropriate.  */
+ 	  break;
+ 
+ 	case wordchar:
+ 	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+ 	    if (SYNTAX (j) == Sword)
+ 	      fastmap[j] = 1;
+ 	  break;
+ 
+ 	case notwordchar:
+ 	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+ 	    if (SYNTAX (j) != Sword)
+ 	      fastmap[j] = 1;
+ 	  break;
+ 
+ #ifdef emacs
+ 	case syntaxspec:
+ 	  k = *p++;
+ 	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+ 	    if (SYNTAX (j) == (enum syntaxcode) k)
+ 	      fastmap[j] = 1;
+ 	  break;
+ 
+ 	case notsyntaxspec:
+ 	  k = *p++;
+ 	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+ 	    if (SYNTAX (j) != (enum syntaxcode) k)
+ 	      fastmap[j] = 1;
+ 	  break;
+ #endif /* emacs */
+ 
+ 	case charset:
+ 	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ 	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+ 	      {
+ 		if (translate)
+ 		  fastmap[translate[j]] = 1;
+ 		else
+ 		  fastmap[j] = 1;
+ 	      }
+ 	  break;
+ 
+ 	case charset_not:
+ 	  /* Chars beyond end of map must be allowed */
+ 	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+ 	    if (translate)
+ 	      fastmap[translate[j]] = 1;
+ 	    else
+ 	      fastmap[j] = 1;
+ 
+ 	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ 	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+ 	      {
+ 		if (translate)
+ 		  fastmap[translate[j]] = 1;
+ 		else
+ 		  fastmap[j] = 1;
+ 	      }
+ 	  break;
+ 	}
+ 
+       /* Get here means we have successfully found the possible starting characters
+ 	 of one path of the pattern.  We need not follow this path any farther.
+ 	 Instead, look at the next alternative remembered in the stack. */
+       if (stackp != stackb)
+ 	p = *stackp--;
+       else
+ 	break;
+     }
+ }
+ 
+ /* Like re_search_2, below, but only one string is specified. */
+ 
+ int
+ re_search (pbufp, string, size, startpos, range, regs)
+      struct re_pattern_buffer *pbufp;
+      char *string;
+      int size, startpos, range;
+      struct re_registers *regs;
+ {
+   return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size);
+ }
+ 
+ /* Like re_match_2 but tries first a match starting at index STARTPOS,
+    then at STARTPOS + 1, and so on.
+    RANGE is the number of places to try before giving up.
+    If RANGE is negative, the starting positions tried are
+     STARTPOS, STARTPOS - 1, etc.
+    It is up to the caller to make sure that range is not so large
+    as to take the starting position outside of the input strings.
+ 
+ The value returned is the position at which the match was found,
+  or -1 if no match was found,
+  or -2 if error (such as failure stack overflow).  */
+ 
+ int
+ re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop)
+      struct re_pattern_buffer *pbufp;
+      char *string1, *string2;
+      int size1, size2;
+      int startpos;
+      register int range;
+      struct re_registers *regs;
+      int mstop;
+ {
+   register char *fastmap = pbufp->fastmap;
+   register unsigned char *translate = (unsigned char *) pbufp->translate;
+   int total = size1 + size2;
+   int val;
+ 
+   /* Update the fastmap now if not correct already */
+   if (fastmap && !pbufp->fastmap_accurate)
+     re_compile_fastmap (pbufp);
+   
+   /* Don't waste time in a long search for a pattern
+      that says it is anchored.  */
+   if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
+       && range > 0)
+     {
+       if (startpos > 0)
+ 	return -1;
+       else
+ 	range = 1;
+     }
+ 
+   while (1)
+     {
+       /* If a fastmap is supplied, skip quickly over characters
+ 	 that cannot possibly be the start of a match.
+ 	 Note, however, that if the pattern can possibly match
+ 	 the null string, we must test it at each starting point
+ 	 so that we take the first null string we get.  */
+ 
+       if (fastmap && startpos < total && pbufp->can_be_null != 1)
+ 	{
+ 	  if (range > 0)
+ 	    {
+ 	      register int lim = 0;
+ 	      register unsigned char *p;
+ 	      int irange = range;
+ 	      if (startpos < size1 && startpos + range >= size1)
+ 		lim = range - (size1 - startpos);
+ 
+ 	      p = ((unsigned char *)
+ 		   &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
+ 
+ 	      if (translate)
+ 		{
+ 		  while (range > lim && !fastmap[translate[*p++]])
+ 		    range--;
+ 		}
+ 	      else
+ 		{
+ 		  while (range > lim && !fastmap[*p++])
+ 		    range--;
+ 		}
+ 	      startpos += irange - range;
+ 	    }
+ 	  else
+ 	    {
+ 	      register unsigned char c;
+ 	      if (startpos >= size1)
+ 		c = string2[startpos - size1];
+ 	      else
+ 		c = string1[startpos];
+ 	      c &= 0xff;
+ 	      if (translate ? !fastmap[translate[c]] : !fastmap[c])
+ 		goto advance;
+ 	    }
+ 	}
+ 
+       if (range >= 0 && startpos == total
+ 	  && fastmap && pbufp->can_be_null == 0)
+ 	return -1;
+ 
+       val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop);
+       if (0 <= val)
+ 	{
+ 	  if (val == -2)
+ 	    return -2;
+ 	  return startpos;
+ 	}
+ 
+ #ifdef C_ALLOCA
+       alloca (0);
+ #endif /* C_ALLOCA */
+ 
+     advance:
+       if (!range) break;
+       if (range > 0) range--, startpos++; else range++, startpos--;
+     }
+   return -1;
+ }
+ 
+ #ifndef emacs   /* emacs never uses this */
+ int
+ re_match (pbufp, string, size, pos, regs)
+      struct re_pattern_buffer *pbufp;
+      char *string;
+      int size, pos;
+      struct re_registers *regs;
+ {
+   return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size);
+ }
+ #endif /* emacs */
+ 
+ /* Maximum size of failure stack.  Beyond this, overflow is an error.  */
+ 
+ int re_max_failures = 2000;
+ 
+ static int bcmp_translate();
+ /* Match the pattern described by PBUFP
+    against data which is the virtual concatenation of STRING1 and STRING2.
+    SIZE1 and SIZE2 are the sizes of the two data strings.
+    Start the match at position POS.
+    Do not consider matching past the position MSTOP.
+ 
+    If pbufp->fastmap is nonzero, then it had better be up to date.
+ 
+    The reason that the data to match are specified as two components
+    which are to be regarded as concatenated
+    is so this function can be used directly on the contents of an Emacs buffer.
+ 
+    -1 is returned if there is no match.  -2 is returned if there is
+    an error (such as match stack overflow).  Otherwise the value is the length
+    of the substring which was matched.  */
+ 
+ int
+ re_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop)
+      struct re_pattern_buffer *pbufp;
+      unsigned char *string1, *string2;
+      int size1, size2;
+      int pos;
+      struct re_registers *regs;
+      int mstop;
+ {
+   register unsigned char *p = (unsigned char *) pbufp->buffer;
+   register unsigned char *pend = p + pbufp->used;
+   /* End of first string */
+   unsigned char *end1;
+   /* End of second string */
+   unsigned char *end2;
+   /* Pointer just past last char to consider matching */
+   unsigned char *end_match_1, *end_match_2;
+   register unsigned char *d, *dend;
+   register int mcnt;
+   unsigned char *translate = (unsigned char *) pbufp->translate;
+ 
+  /* Failure point stack.  Each place that can handle a failure further down the line
+     pushes a failure point on this stack.  It consists of two char *'s.
+     The first one pushed is where to resume scanning the pattern;
+     the second pushed is where to resume scanning the strings.
+     If the latter is zero, the failure point is a "dummy".
+     If a failure happens and the innermost failure point is dormant,
+     it discards that failure point and tries the next one. */
+ 
+   unsigned char *initial_stack[2 * NFAILURES];
+   unsigned char **stackb = initial_stack;
+   unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES];
+ 
+   /* Information on the "contents" of registers.
+      These are pointers into the input strings; they record
+      just what was matched (on this attempt) by some part of the pattern.
+      The start_memory command stores the start of a register's contents
+      and the stop_memory command stores the end.
+ 
+      At that point, regstart[regnum] points to the first character in the register,
+      regend[regnum] points to the first character beyond the end of the register,
+      regstart_seg1[regnum] is true iff regstart[regnum] points into string1,
+      and regend_seg1[regnum] is true iff regend[regnum] points into string1.  */
+ 
+   unsigned char *regstart[RE_NREGS];
+   unsigned char *regend[RE_NREGS];
+   unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS];
+ 
+   /* Set up pointers to ends of strings.
+      Don't allow the second string to be empty unless both are empty.  */
+   if (!size2)
+     {
+       string2 = string1;
+       size2 = size1;
+       string1 = 0;
+       size1 = 0;
+     }
+   end1 = string1 + size1;
+   end2 = string2 + size2;
+ 
+   /* Compute where to stop matching, within the two strings */
+   if (mstop <= size1)
+     {
+       end_match_1 = string1 + mstop;
+       end_match_2 = string2;
+     }
+   else
+     {
+       end_match_1 = end1;
+       end_match_2 = string2 + mstop - size1;
+     }
+ 
+   /* Initialize \) text positions to -1
+      to mark ones that no \( or \) has been seen for.  */
+ 
+   for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++)
+     regend[mcnt] = (unsigned char *) -1;
+ 
+   /* `p' scans through the pattern as `d' scans through the data.
+      `dend' is the end of the input string that `d' points within.
+      `d' is advanced into the following input string whenever necessary,
+      but this happens before fetching;
+      therefore, at the beginning of the loop,
+      `d' can be pointing at the end of a string,
+      but it cannot equal string2.  */
+ 
+   if (pos <= size1)
+     d = string1 + pos, dend = end_match_1;
+   else
+     d = string2 + pos - size1, dend = end_match_2;
+ 
+ /* Write PREFETCH; just before fetching a character with *d.  */
+ #define PREFETCH \
+  while (d == dend)						    \
+   { if (dend == end_match_2) goto fail;  /* end of string2 => failure */   \
+     d = string2;  /* end of string1 => advance to string2. */       \
+     dend = end_match_2; }
+ 
+   /* This loop loops over pattern commands.
+      It exits by returning from the function if match is complete,
+      or it drops through if match fails at this starting point in the input data. */
+ 
+   while (1)
+     {
+       if (p == pend)
+ 	/* End of pattern means we have succeeded! */
+ 	{
+ 	  /* If caller wants register contents data back, convert it to indices */
+ 	  if (regs)
+ 	    {
+  	      regs->start[0] = pos;
+  	      if (dend == end_match_1)
+  		regs->end[0] = d - string1;
+  	      else
+  		regs->end[0] = d - string2 + size1;
+  	      for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ 		{
+ 		  if (regend[mcnt] == (unsigned char *) -1)
+ 		    {
+ 		      regs->start[mcnt] = -1;
+ 		      regs->end[mcnt] = -1;
+ 		      continue;
+ 		    }
+  		  if (regstart_seg1[mcnt])
+ 		    regs->start[mcnt] = regstart[mcnt] - string1;
+ 		  else
+ 		    regs->start[mcnt] = regstart[mcnt] - string2 + size1;
+  		  if (regend_seg1[mcnt])
+ 		    regs->end[mcnt] = regend[mcnt] - string1;
+ 		  else
+ 		    regs->end[mcnt] = regend[mcnt] - string2 + size1;
+ 		}
+ 	    }
+  	  if (dend == end_match_1)
+ 	    return (d - string1 - pos);
+ 	  else
+ 	    return d - string2 + size1 - pos;
+ 	}
+ 
+       /* Otherwise match next pattern command */
+ #ifdef SWITCH_ENUM_BUG
+       switch ((int) ((enum regexpcode) *p++))
+ #else
+       switch ((enum regexpcode) *p++)
+ #endif
+ 	{
+ 
+ 	/* \( is represented by a start_memory, \) by a stop_memory.
+ 	    Both of those commands contain a "register number" argument.
+ 	    The text matched within the \( and \) is recorded under that number.
+ 	    Then, \<digit> turns into a `duplicate' command which
+ 	    is followed by the numeric value of <digit> as the register number. */
+ 
+ 	case start_memory:
+ 	  regstart[*p] = d;
+  	  regstart_seg1[*p++] = (dend == end_match_1);
+ 	  break;
+ 
+ 	case stop_memory:
+ 	  regend[*p] = d;
+  	  regend_seg1[*p++] = (dend == end_match_1);
+ 	  break;
+ 
+ 	case duplicate:
+ 	  {
+ 	    int regno = *p++;   /* Get which register to match against */
+ 	    register unsigned char *d2, *dend2;
+ 
+ 	    d2 = regstart[regno];
+  	    dend2 = ((regstart_seg1[regno] == regend_seg1[regno])
+ 		     ? regend[regno] : end_match_1);
+ 	    while (1)
+ 	      {
+ 		/* Advance to next segment in register contents, if necessary */
+ 		while (d2 == dend2)
+ 		  {
+ 		    if (dend2 == end_match_2) break;
+ 		    if (dend2 == regend[regno]) break;
+ 		    d2 = string2, dend2 = regend[regno];  /* end of string1 => advance to string2. */
+ 		  }
+ 		/* At end of register contents => success */
+ 		if (d2 == dend2) break;
+ 
+ 		/* Advance to next segment in data being matched, if necessary */
+ 		PREFETCH;
+ 
+ 		/* mcnt gets # consecutive chars to compare */
+ 		mcnt = dend - d;
+ 		if (mcnt > dend2 - d2)
+ 		  mcnt = dend2 - d2;
+ 		/* Compare that many; failure if mismatch, else skip them. */
+ 		if (translate ? bcmp_translate (d, d2, mcnt, translate) : bcmp (d, d2, mcnt))
+ 		  goto fail;
+ 		d += mcnt, d2 += mcnt;
+ 	      }
+ 	  }
+ 	  break;
+ 
+ 	case anychar:
+ 	  /* fetch a data character */
+ 	  PREFETCH;
+ 	  /* Match anything but a newline.  */
+ 	  if ((translate ? translate[*d++] : *d++) == '\n')
+ 	    goto fail;
+ 	  break;
+ 
+ 	case charset:
+ 	case charset_not:
+ 	  {
+ 	    /* Nonzero for charset_not */
+ 	    int not = 0;
+ 	    register int c;
+ 	    if (*(p - 1) == (unsigned char) charset_not)
+ 	      not = 1;
+ 
+ 	    /* fetch a data character */
+ 	    PREFETCH;
+ 
+ 	    if (translate)
+ 	      c = translate [*d];
+ 	    else
+ 	      c = *d;
+ 
+ 	    if (c < *p * BYTEWIDTH
+ 		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ 	      not = !not;
+ 
+ 	    p += 1 + *p;
+ 
+ 	    if (!not) goto fail;
+ 	    d++;
+ 	    break;
+ 	  }
+ 
+ 	case begline:
+ 	  if (d == string1 || d[-1] == '\n')
+ 	    break;
+ 	  goto fail;
+ 
+ 	case endline:
+ 	  if (d == end2
+ 	      || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
+ 	    break;
+ 	  goto fail;
+ 
+ 	/* "or" constructs ("|") are handled by starting each alternative
+ 	    with an on_failure_jump that points to the start of the next alternative.
+ 	    Each alternative except the last ends with a jump to the joining point.
+ 	    (Actually, each jump except for the last one really jumps
+ 	     to the following jump, because tensioning the jumps is a hassle.) */
+ 
+ 	/* The start of a stupid repeat has an on_failure_jump that points
+ 	   past the end of the repeat text.
+ 	   This makes a failure point so that, on failure to match a repetition,
+ 	   matching restarts past as many repetitions have been found
+ 	   with no way to fail and look for another one.  */
+ 
+ 	/* A smart repeat is similar but loops back to the on_failure_jump
+ 	   so that each repetition makes another failure point. */
+ 
+ 	case on_failure_jump:
+ 	  if (stackp == stacke)
+ 	    {
+ 	      unsigned char **stackx;
+ 	      if (stacke - stackb > re_max_failures * 2)
+ 		return -2;
+ 	      stackx = (unsigned char **) alloca (2 * (stacke - stackb)
+ 					 * sizeof (char *));
+ 	      bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
+ 	      stackp = stackx + (stackp - stackb);
+ 	      stacke = stackx + 2 * (stacke - stackb);
+ 	      stackb = stackx;
+ 	    }
+ 	  mcnt = *p++ & 0377;
+ 	  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ 	  p++;
+ 	  *stackp++ = mcnt + p;
+ 	  *stackp++ = d;
+ 	  break;
+ 
+ 	/* The end of a smart repeat has an maybe_finalize_jump back.
+ 	   Change it either to a finalize_jump or an ordinary jump. */
+ 
+ 	case maybe_finalize_jump:
+ 	  mcnt = *p++ & 0377;
+ 	  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ 	  p++;
+ 	  {
+ 	    register unsigned char *p2 = p;
+ 	    /* Compare what follows with the begining of the repeat.
+ 	       If we can establish that there is nothing that they would
+ 	       both match, we can change to finalize_jump */
+ 	    while (p2 != pend
+ 		   && (*p2 == (unsigned char) stop_memory
+ 		       || *p2 == (unsigned char) start_memory))
+ 	      p2++;
+ 	    if (p2 == pend)
+ 	      p[-3] = (unsigned char) finalize_jump;
+ 	    else if (*p2 == (unsigned char) exactn
+ 		     || *p2 == (unsigned char) endline)
+ 	      {
+ 		register int c = *p2 == (unsigned char) endline ? '\n' : p2[2];
+ 		register unsigned char *p1 = p + mcnt;
+ 		/* p1[0] ... p1[2] are an on_failure_jump.
+ 		   Examine what follows that */
+ 		if (p1[3] == (unsigned char) exactn && p1[5] != c)
+ 		  p[-3] = (unsigned char) finalize_jump;
+ 		else if (p1[3] == (unsigned char) charset
+ 			 || p1[3] == (unsigned char) charset_not)
+ 		  {
+ 		    int not = p1[3] == (unsigned char) charset_not;
+ 		    if (c < p1[4] * BYTEWIDTH
+ 			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ 		      not = !not;
+ 		    /* not is 1 if c would match */
+ 		    /* That means it is not safe to finalize */
+ 		    if (!not)
+ 		      p[-3] = (unsigned char) finalize_jump;
+ 		  }
+ 	      }
+ 	  }
+ 	  p -= 2;
+ 	  if (p[-1] != (unsigned char) finalize_jump)
+ 	    {
+ 	      p[-1] = (unsigned char) jump;
+ 	      goto nofinalize;
+ 	    }
+ 
+ 	/* The end of a stupid repeat has a finalize-jump
+ 	   back to the start, where another failure point will be made
+ 	   which will point after all the repetitions found so far. */
+ 
+ 	case finalize_jump:
+ 	  stackp -= 2;
+ 
+ 	case jump:
+ 	nofinalize:
+ 	  mcnt = *p++ & 0377;
+ 	  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ 	  p += mcnt + 1;	/* The 1 compensates for missing ++ above */
+ 	  break;
+ 
+ 	case dummy_failure_jump:
+ 	  if (stackp == stacke)
+ 	    {
+ 	      unsigned char **stackx
+ 		= (unsigned char **) alloca (2 * (stacke - stackb)
+ 					     * sizeof (char *));
+ 	      bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
+ 	      stackp = stackx + (stackp - stackb);
+ 	      stacke = stackx + 2 * (stacke - stackb);
+ 	      stackb = stackx;
+ 	    }
+ 	  *stackp++ = 0;
+ 	  *stackp++ = 0;
+ 	  goto nofinalize;
+ 
+ 	case wordbound:
+ 	  if (d == string1  /* Points to first char */
+ 	      || d == end2  /* Points to end */
+ 	      || (d == end1 && size2 == 0)) /* Points to end */
+ 	    break;
+ 	  if ((SYNTAX (d[-1]) == Sword)
+ 	      != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ 	    break;
+ 	  goto fail;
+ 
+ 	case notwordbound:
+ 	  if (d == string1  /* Points to first char */
+ 	      || d == end2  /* Points to end */
+ 	      || (d == end1 && size2 == 0)) /* Points to end */
+ 	    goto fail;
+ 	  if ((SYNTAX (d[-1]) == Sword)
+ 	      != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ 	    goto fail;
+ 	  break;
+ 
+ 	case wordbeg:
+ 	  if (d == end2  /* Points to end */
+ 	      || (d == end1 && size2 == 0) /* Points to end */
+ 	      || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */
+ 	    goto fail;
+ 	  if (d == string1  /* Points to first char */
+ 	      || SYNTAX (d[-1]) != Sword)  /* prev char not letter */
+ 	    break;
+ 	  goto fail;
+ 
+ 	case wordend:
+ 	  if (d == string1  /* Points to first char */
+ 	      || SYNTAX (d[-1]) != Sword)  /* prev char not letter */
+ 	    goto fail;
+ 	  if (d == end2  /* Points to end */
+ 	      || (d == end1 && size2 == 0) /* Points to end */
+ 	      || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */
+ 	    break;
+ 	  goto fail;
+ 
+ #ifdef emacs
+ 	case before_dot:
+ 	  if (((d - string2 <= (unsigned) size2)
+ 	       ? d - bf_p2 : d - bf_p1)
+ 	      <= point)
+ 	    goto fail;
+ 	  break;
+ 
+ 	case at_dot:
+ 	  if (((d - string2 <= (unsigned) size2)
+ 	       ? d - bf_p2 : d - bf_p1)
+ 	      == point)
+ 	    goto fail;
+ 	  break;
+ 
+ 	case after_dot:
+ 	  if (((d - string2 <= (unsigned) size2)
+ 	       ? d - bf_p2 : d - bf_p1)
+ 	      >= point)
+ 	    goto fail;
+ 	  break;
+ 
+ 	case wordchar:
+ 	  mcnt = (int) Sword;
+ 	  goto matchsyntax;
+ 
+ 	case syntaxspec:
+ 	  mcnt = *p++;
+ 	matchsyntax:
+ 	  PREFETCH;
+ 	  if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
+ 	  break;
+ 	  
+ 	case notwordchar:
+ 	  mcnt = (int) Sword;
+ 	  goto matchnotsyntax;
+ 
+ 	case notsyntaxspec:
+ 	  mcnt = *p++;
+ 	matchnotsyntax:
+ 	  PREFETCH;
+ 	  if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
+ 	  break;
+ #else
+ 	case wordchar:
+ 	  PREFETCH;
+ 	  if (SYNTAX (*d++) == 0) goto fail;
+ 	  break;
+ 	  
+ 	case notwordchar:
+ 	  PREFETCH;
+ 	  if (SYNTAX (*d++) != 0) goto fail;
+ 	  break;
+ #endif /* not emacs */
+ 
+ 	case begbuf:
+ 	  if (d == string1)	/* Note, d cannot equal string2 */
+ 	    break;		/* unless string1 == string2.  */
+ 	  goto fail;
+ 
+ 	case endbuf:
+ 	  if (d == end2 || (d == end1 && size2 == 0))
+ 	    break;
+ 	  goto fail;
+ 
+ 	case exactn:
+ 	  /* Match the next few pattern characters exactly.
+ 	     mcnt is how many characters to match. */
+ 	  mcnt = *p++;
+ 	  if (translate)
+ 	    {
+ 	      do
+ 		{
+ 		  PREFETCH;
+ 		  if (translate[*d++] != *p++) goto fail;
+ 		}
+ 	      while (--mcnt);
+ 	    }
+ 	  else
+ 	    {
+ 	      do
+ 		{
+ 		  PREFETCH;
+ 		  if (*d++ != *p++) goto fail;
+ 		}
+ 	      while (--mcnt);
+ 	    }
+ 	  break;
+ 	}
+       continue;    /* Successfully matched one pattern command; keep matching */
+ 
+       /* Jump here if any matching operation fails. */
+     fail:
+       if (stackp != stackb)
+ 	/* A restart point is known.  Restart there and pop it. */
+ 	{
+ 	  if (!stackp[-2])
+ 	    {   /* If innermost failure point is dormant, flush it and keep looking */
+ 	      stackp -= 2;
+ 	      goto fail;
+ 	    }
+ 	  d = *--stackp;
+ 	  p = *--stackp;
+ 	  if (d >= string1 && d <= end1)
+ 	    dend = end_match_1;
+ 	}
+       else break;   /* Matching at this starting point really fails! */
+     }
+   return -1;         /* Failure to match */
+ }
+ 
+ static int
+ bcmp_translate (s1, s2, len, translate)
+      unsigned char *s1, *s2;
+      register int len;
+      unsigned char *translate;
+ {
+   register unsigned char *p1 = s1, *p2 = s2;
+   while (len)
+     {
+       if (translate [*p1++] != translate [*p2++]) return 1;
+       len--;
+     }
+   return 0;
+ }
+ 
+ /* Entry points compatible with bsd4.2 regex library */
+ 
+ #ifndef emacs
+ 
+ static struct re_pattern_buffer re_comp_buf;
+ 
+ char *
+ re_comp (s)
+      char *s;
+ {
+   if (!s)
+     {
+       if (!re_comp_buf.buffer)
+ 	return "No previous regular expression";
+       return 0;
+     }
+ 
+   if (!re_comp_buf.buffer)
+     {
+       if (!(re_comp_buf.buffer = (char *) malloc (200)))
+ 	return "Memory exhausted";
+       re_comp_buf.allocated = 200;
+       if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
+ 	return "Memory exhausted";
+     }
+   return re_compile_pattern (s, strlen (s), &re_comp_buf);
+ }
+ 
+ int
+ re_exec (s)
+      char *s;
+ {
+   int len = strlen (s);
+   return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0);
+ }
+ 
+ #endif /* emacs */
+ 
+ #ifdef test
+ 
+ #include <stdio.h>
+ 
+ /* Indexed by a character, gives the upper case equivalent of the character */
+ 
+ static char upcase[0400] = 
+   { 000, 001, 002, 003, 004, 005, 006, 007,
+     010, 011, 012, 013, 014, 015, 016, 017,
+     020, 021, 022, 023, 024, 025, 026, 027,
+     030, 031, 032, 033, 034, 035, 036, 037,
+     040, 041, 042, 043, 044, 045, 046, 047,
+     050, 051, 052, 053, 054, 055, 056, 057,
+     060, 061, 062, 063, 064, 065, 066, 067,
+     070, 071, 072, 073, 074, 075, 076, 077,
+     0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
+     0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
+     0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
+     0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
+     0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
+     0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
+     0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
+     0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
+     0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+     0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+     0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+     0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+     0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+     0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+     0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+     0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+     0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+     0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+     0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+     0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+     0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+     0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+     0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+     0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
+   };
+ 
+ main (argc, argv)
+      int argc;
+      char **argv;
+ {
+   char pat[80];
+   struct re_pattern_buffer buf;
+   int i;
+   char c;
+   char fastmap[(1 << BYTEWIDTH)];
+ 
+   /* Allow a command argument to specify the style of syntax.  */
+   if (argc > 1)
+     obscure_syntax = atoi (argv[1]);
+ 
+   buf.allocated = 40;
+   buf.buffer = (char *) malloc (buf.allocated);
+   buf.fastmap = fastmap;
+   buf.translate = upcase;
+ 
+   while (1)
+     {
+       gets (pat);
+ 
+       if (*pat)
+ 	{
+           re_compile_pattern (pat, strlen(pat), &buf);
+ 
+ 	  for (i = 0; i < buf.used; i++)
+ 	    printchar (buf.buffer[i]);
+ 
+ 	  putchar ('\n');
+ 
+ 	  printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
+ 
+ 	  re_compile_fastmap (&buf);
+ 	  printf ("Allowed by fastmap: ");
+ 	  for (i = 0; i < (1 << BYTEWIDTH); i++)
+ 	    if (fastmap[i]) printchar (i);
+ 	  putchar ('\n');
+ 	}
+ 
+       gets (pat);	/* Now read the string to match against */
+ 
+       i = re_match (&buf, pat, strlen (pat), 0, 0);
+       printf ("Match value %d.\n", i);
+     }
+ }
+ 
+ #ifdef NOTDEF
+ print_buf (bufp)
+      struct re_pattern_buffer *bufp;
+ {
+   int i;
+ 
+   printf ("buf is :\n----------------\n");
+   for (i = 0; i < bufp->used; i++)
+     printchar (bufp->buffer[i]);
+   
+   printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
+   
+   printf ("Allowed by fastmap: ");
+   for (i = 0; i < (1 << BYTEWIDTH); i++)
+     if (bufp->fastmap[i])
+       printchar (i);
+   printf ("\nAllowed by translate: ");
+   if (bufp->translate)
+     for (i = 0; i < (1 << BYTEWIDTH); i++)
+       if (bufp->translate[i])
+ 	printchar (i);
+   printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
+   printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
+ }
+ #endif
+ 
+ printchar (c)
+      char c;
+ {
+   if (c < 041 || c >= 0177)
+     {
+       putchar ('\\');
+       putchar (((c >> 6) & 3) + '0');
+       putchar (((c >> 3) & 7) + '0');
+       putchar ((c & 7) + '0');
+     }
+   else
+     putchar (c);
+ }
+ 
+ #endif /* test */


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/regex.h
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/regex.h:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/regex.h	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,274 ----
+ /* Definitions for data structures callers pass the regex library.
+    Copyright (C) 1985 Free Software Foundation, Inc.
+ 
+ 		       NO WARRANTY
+ 
+   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+ NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
+ WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
+ RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
+ AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
+ DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+ CORRECTION.
+ 
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+ STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
+ WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
+ OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+ USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
+ DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
+ A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
+ PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
+ 
+ 		GENERAL PUBLIC LICENSE TO COPY
+ 
+   1. You may copy and distribute verbatim copies of this source file
+ as you receive it, in any medium, provided that you conspicuously and
+ appropriately publish on each copy a valid copyright notice "Copyright
+ (C) 1985 Free Software Foundation, Inc."; and include following the
+ copyright notice a verbatim copy of the above disclaimer of warranty
+ and of this License.  You may charge a distribution fee for the
+ physical act of transferring a copy.
+ 
+   2. You may modify your copy or copies of this source file or
+ any portion of it, and copy and distribute such modifications under
+ the terms of Paragraph 1 above, provided that you also do the following:
+ 
+     a) cause the modified files to carry prominent notices stating
+     that you changed the files and the date of any change; and
+ 
+     b) cause the whole of any work that you distribute or publish,
+     that in whole or in part contains or is a derivative of this
+     program or any part thereof, to be licensed at no charge to all
+     third parties on terms identical to those contained in this
+     License Agreement (except that you may choose to grant more extensive
+     warranty protection to some or all third parties, at your option).
+ 
+     c) You may charge a distribution fee for the physical act of
+     transferring a copy, and you may at your option offer warranty
+     protection in exchange for a fee.
+ 
+ Mere aggregation of another unrelated program with this program (or its
+ derivative) on a volume of a storage or distribution medium does not bring
+ the other program under the scope of these terms.
+ 
+   3. You may copy and distribute this program (or a portion or derivative
+ of it, under Paragraph 2) in object code or executable form under the terms
+ of Paragraphs 1 and 2 above provided that you also do one of the following:
+ 
+     a) accompany it with the complete corresponding machine-readable
+     source code, which must be distributed under the terms of
+     Paragraphs 1 and 2 above; or,
+ 
+     b) accompany it with a written offer, valid for at least three
+     years, to give any third party free (except for a nominal
+     shipping charge) a complete machine-readable copy of the
+     corresponding source code, to be distributed under the terms of
+     Paragraphs 1 and 2 above; or,
+ 
+     c) accompany it with the information you received as to where the
+     corresponding source code may be obtained.  (This alternative is
+     allowed only for noncommercial distribution and only if you
+     received the program in object code or executable form alone.)
+ 
+ For an executable file, complete source code means all the source code for
+ all modules it contains; but, as a special exception, it need not include
+ source code for modules which are standard libraries that accompany the
+ operating system on which the executable file runs.
+ 
+   4. You may not copy, sublicense, distribute or transfer this program
+ except as expressly provided under this License Agreement.  Any attempt
+ otherwise to copy, sublicense, distribute or transfer this program is void and
+ your rights to use the program under this License agreement shall be
+ automatically terminated.  However, parties who have received computer
+ software programs from you with this License Agreement will not have
+ their licenses terminated so long as such parties remain in full compliance.
+ 
+   5. If you wish to incorporate parts of this program into other free
+ programs whose distribution conditions are different, write to the Free
+ Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
+ worked out a simple rule that can be stated here, but we will often permit
+ this.  We will be guided by the two goals of preserving the free status of
+ all derivatives of our free software and of promoting the sharing and reuse of
+ software.
+ 
+ 
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them.   Help stamp out software-hoarding!  */
+ 
+ 
+ /* Define number of parens for which we record the beginnings and ends.
+    This affects how much space the `struct re_registers' type takes up.  */
+ #ifndef RE_NREGS
+ #define RE_NREGS 10
+ #endif
+ 
+ /* These bits are used in the obscure_syntax variable to choose among
+    alternative regexp syntaxes.  */
+ 
+ /* 1 means plain parentheses serve as grouping, and backslash
+      parentheses are needed for literal searching.
+    0 means backslash-parentheses are grouping, and plain parentheses
+      are for literal searching.  */
+ #define RE_NO_BK_PARENS 1
+ 
+ /* 1 means plain | serves as the "or"-operator, and \| is a literal.
+    0 means \| serves as the "or"-operator, and | is a literal.  */
+ #define RE_NO_BK_VBAR 2
+ 
+ /* 0 means plain + or ? serves as an operator, and \+, \? are literals.
+    1 means \+, \? are operators and plain +, ? are literals.  */
+ #define RE_BK_PLUS_QM 4
+ 
+ /* 1 means | binds tighter than ^ or $.
+    0 means the contrary.  */
+ #define RE_TIGHT_VBAR 8
+ 
+ /* 1 means treat \n as an _OR operator
+    0 means treat it as a normal character */
+ #define RE_NEWLINE_OR 16
+ 
+ /* 0 means that a special characters (such as *, ^, and $) always have
+      their special meaning regardless of the surrounding context.
+    1 means that special characters may act as normal characters in some
+      contexts.  Specifically, this applies to:
+ 	^ - only special at the beginning, or after ( or |
+ 	$ - only special at the end, or before ) or |
+ 	*, +, ? - only special when not after the beginning, (, or | */
+ #define RE_CONTEXT_INDEP_OPS 32
+ 
+ /* 0 means that \ before anything inside [ and ] is taken as a real \.
+    1 means that such a \ escapes the following character  This is a
+    special case for AWK. */
+ #define RE_AWK_CLASS_HACK 64
+ 
+ /* Now define combinations of bits for the standard possibilities.  */
+ #define RE_SYNTAX_POSIX_EGREP (RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ 			| RE_CONTEXT_INDEP_OPS)
+ #define RE_SYNTAX_AWK (RE_SYNTAX_POSIX_EGREP | RE_AWK_CLASS_HACK)
+ #define RE_SYNTAX_EGREP (RE_SYNTAX_POSIX_EGREP | RE_NEWLINE_OR)
+ #define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
+ #define RE_SYNTAX_EMACS 0
+ 
+ /* This data structure is used to represent a compiled pattern. */
+ 
+ struct re_pattern_buffer
+   {
+     char *buffer;	/* Space holding the compiled pattern commands. */
+     int allocated;	/* Size of space that  buffer  points to */
+     int used;		/* Length of portion of buffer actually occupied */
+     char *fastmap;	/* Pointer to fastmap, if any, or zero if none. */
+ 			/* re_search uses the fastmap, if there is one,
+ 			   to skip quickly over totally implausible characters */
+     char *translate;	/* Translate table to apply to all characters before comparing.
+ 			   Or zero for no translation.
+ 			   The translation is applied to a pattern when it is compiled
+ 			   and to data when it is matched. */
+     char fastmap_accurate;
+ 			/* Set to zero when a new pattern is stored,
+ 			   set to one when the fastmap is updated from it. */
+     char can_be_null;   /* Set to one by compiling fastmap
+ 			   if this pattern might match the null string.
+ 			   It does not necessarily match the null string
+ 			   in that case, but if this is zero, it cannot.
+ 			   2 as value means can match null string
+ 			   but at end of range or before a character
+ 			   listed in the fastmap.  */
+   };
+ 
+ /* Structure to store "register" contents data in.
+ 
+    Pass the address of such a structure as an argument to re_match, etc.,
+    if you want this information back.
+ 
+    start[i] and end[i] record the string matched by \( ... \) grouping i,
+    for i from 1 to RE_NREGS - 1.
+    start[0] and end[0] record the entire string matched. */
+ 
+ struct re_registers
+   {
+     int start[RE_NREGS];
+     int end[RE_NREGS];
+   };
+ 
+ /* These are the command codes that appear in compiled regular expressions, one per byte.
+   Some command codes are followed by argument bytes.
+   A command code can specify any interpretation whatever for its arguments.
+   Zero-bytes may appear in the compiled regular expression. */
+ 
+ enum regexpcode
+   {
+     unused,
+     exactn,    /* followed by one byte giving n, and then by n literal bytes */
+     begline,   /* fails unless at beginning of line */
+     endline,   /* fails unless at end of line */
+     jump,	 /* followed by two bytes giving relative address to jump to */
+     on_failure_jump,	 /* followed by two bytes giving relative address of place
+ 		            to resume at in case of failure. */
+     finalize_jump,	 /* Throw away latest failure point and then jump to address. */
+     maybe_finalize_jump, /* Like jump but finalize if safe to do so.
+ 			    This is used to jump back to the beginning
+ 			    of a repeat.  If the command that follows
+ 			    this jump is clearly incompatible with the
+ 			    one at the beginning of the repeat, such that
+ 			    we can be sure that there is no use backtracking
+ 			    out of repetitions already completed,
+ 			    then we finalize. */
+     dummy_failure_jump,  /* jump, and push a dummy failure point.
+ 			    This failure point will be thrown away
+ 			    if an attempt is made to use it for a failure.
+ 			    A + construct makes this before the first repeat.  */
+     anychar,	 /* matches any one character */
+     charset,     /* matches any one char belonging to specified set.
+ 		    First following byte is # bitmap bytes.
+ 		    Then come bytes for a bit-map saying which chars are in.
+ 		    Bits in each byte are ordered low-bit-first.
+ 		    A character is in the set if its bit is 1.
+ 		    A character too large to have a bit in the map
+ 		    is automatically not in the set */
+     charset_not, /* similar but match any character that is NOT one of those specified */
+     start_memory, /* starts remembering the text that is matched
+ 		    and stores it in a memory register.
+ 		    followed by one byte containing the register number.
+ 		    Register numbers must be in the range 0 through NREGS. */
+     stop_memory, /* stops remembering the text that is matched
+ 		    and stores it in a memory register.
+ 		    followed by one byte containing the register number.
+ 		    Register numbers must be in the range 0 through NREGS. */
+     duplicate,    /* match a duplicate of something remembered.
+ 		    Followed by one byte containing the index of the memory register. */
+     before_dot,	 /* Succeeds if before dot */
+     at_dot,	 /* Succeeds if at dot */
+     after_dot,	 /* Succeeds if after dot */
+     begbuf,      /* Succeeds if at beginning of buffer */
+     endbuf,      /* Succeeds if at end of buffer */
+     wordchar,    /* Matches any word-constituent character */
+     notwordchar, /* Matches any char that is not a word-constituent */
+     wordbeg,	 /* Succeeds if at word beginning */
+     wordend,	 /* Succeeds if at word end */
+     wordbound,   /* Succeeds if at a word boundary */
+     notwordbound, /* Succeeds if not at a word boundary */
+     syntaxspec,  /* Matches any character whose syntax is specified.
+ 		    followed by a byte which contains a syntax code, Sword or such like */
+     notsyntaxspec /* Matches any character whose syntax differs from the specified. */
+   };
+ 
+ extern char *re_compile_pattern ();
+ /* Is this really advertised? */
+ extern void re_compile_fastmap ();
+ extern int re_search (), re_search_2 ();
+ extern int re_match (), re_match_2 ();
+ 
+ /* 4.2 bsd compatibility (yuck) */
+ extern char *re_comp ();
+ extern int re_exec ();
+ 
+ #ifdef SYNTAX_TABLE
+ extern char *re_syntax_table;
+ #endif


Index: llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/version.sh
diff -c /dev/null llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/version.sh:1.1.2.1
*** /dev/null	Mon Mar  1 17:59:21 2004
--- llvm/test/Programs/MultiSource/Benchmarks/MallocBench/gawk/version.sh	Mon Mar  1 17:59:10 2004
***************
*** 0 ****
--- 1,49 ----
+ #! /bin/sh
+ 
+ # version.sh --- create version.c
+ 
+ if [ "x$1" = "x" ]
+ then
+ 	echo you must specify a release number on the command line
+ 	exit 1
+ fi
+ 
+ RELEASE="$1"
+ 
+ cat << EOF
+ char *version_string = "@(#)Gnu Awk (gawk) ${RELEASE}";
+ 
+ /* 1.02		fixed /= += *= etc to return the new Left Hand Side instead
+ 		of the Right Hand Side */
+ 
+ /* 1.03		Fixed split() to treat strings of space and tab as FS if
+ 		the split char is ' '.
+ 
+ 		Added -v option to print version number
+  		
+ 		Fixed bug that caused rounding when printing large numbers  */
+ 
+ /* 2.00beta	Incorporated the functionality of the "new" awk as described
+ 		the book (reference not handy).  Extensively tested, but no 
+ 		doubt still buggy.  Badly needs tuning and cleanup, in
+ 		particular in memory management which is currently almost
+ 		non-existent. */
+ 
+ /* 2.01		JF:  Modified to compile under GCC, and fixed a few
+ 		bugs while I was at it.  I hope I didn't add any more.
+ 		I modified parse.y to reduce the number of reduce/reduce
+ 		conflicts.  There are still a few left. */
+ 
+ /* 2.02		Fixed JF's bugs; improved memory management, still needs
+ 		lots of work. */
+ 
+ /* 2.10		Major grammar rework and lots of bug fixes from David.
+ 		Major changes for performance enhancements from David.
+ 		A number of minor bug fixes and new features from Arnold.
+ 		Changes for MSDOS from Conrad Kwok and Scott Garfinkle.
+ 		The gawk.texinfo and info files included! */
+ 
+ /* 2.11		Bug fix release to 2.10.  Lots of changes for portability,
+ 		speed, and configurability.  */
+ EOF
+ exit 0





More information about the llvm-commits mailing list