/* cCoder - produce C code from type-checked parse tree. */

#include "common.h"
#include "linefile.h"
#include "hash.h"
#include "dystring.h"
#include "pfType.h"
#include "pfScope.h"
#include "pfToken.h"
#include "pfCompile.h"
#include "pfParse.h"
#include "recodedType.h"
#include "codedType.h"
#include "ctar.h"
#include "refCount.h"
#include "cMain.h"
#include "cCoder.h"

#define localPrefix "_pf_l."

void codeStatement(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp);
/* Emit code for one statement. */

int codeExpression(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, boolean addRef);
/* Emit code for one expression.  Returns how many items added
 * to stack. */

static void codeScope(struct pfCompile *pfc, FILE *f, struct pfParse *pp, 
	boolean isModuleScope, struct ctar *ctarList);
/* Print types and then variables from scope. */

static char *moduleCleanupName = "_pf_moduleCleanup";



static void cPrintModuleCleanupPrototype(FILE *f)
/* Print function prototype for module cleanup routine. */
{
fprintf(f, "static void %s(struct %s *module, %s *stack)",
	moduleCleanupName, cModuleRuntimeType, cStackType);
}

static void codeLocalTypeRef(FILE *f, int ref)
/* Print out local type reference. */
{
fprintf(f, "%s[%d].id", recodedTypeTableName, ref);
}

static void codeForType(struct pfCompile *pfc, FILE *f, struct pfType *type)
/* Print out code to access type ID */
{
codeLocalTypeRef(f, recodedTypeId(pfc, type));
}

static void codeRunTimeError(FILE *f, struct pfParse *pp, char *message)
/* Print code for a run time error message. */
{
char *file;
struct pfToken *tok = pp->tok;
int line, col;
pfSourcePos(tok->source, tok->text, &file, &line, &col);
fprintf(f, "_pf_run_err(\"Run time error line %d col %d of %s: %s\");\n", 
	line+1, col+1, file, message);
}

static void codeUseOfNil(FILE *f, struct pfParse *pp)
/* Print code for use of nil message. */
{
codeRunTimeError(f, pp, "using uninitialized variable");
}

static void codeNilCheck(FILE *f, struct pfParse *pp, int stack)
/* Print code to check stack for nil. */
{
fprintf(f, "if (%s[%d].v == 0) ", cStackName, stack);
codeUseOfNil(f, pp);
}

static char *typeKey(struct pfCompile *pfc, struct pfBaseType *base)
/* Return key for type if available, or NULL */
{
if (base == pfc->bitType)
    return "Bit";
else if (base == pfc->byteType)
    return "Byte";
else if (base == pfc->shortType)
    return "Short";
else if (base == pfc->intType)
    return "Int";
else if (base == pfc->longType)
    return "Long";
else if (base == pfc->floatType)
    return "Float";
else if (base == pfc->doubleType)
    return "Double";
else if (base == pfc->charType)
    return "Char";
else if (base == pfc->stringType || base == pfc->dyStringType)
    return "String";
else if (base == pfc->varType)
    return "Var";
else if (base == pfc->arrayType)
    return "Array";
else if (base == pfc->dirType)
    return "Dir";
//else if (base == pfc->listType)
//   return "List";
//else if (base == pfc->treeType)
//    return "Tree";
else if (base == pfc->toPtType)
    return "FunctionPt";
else if (base == pfc->flowPtType)
    return "FunctionPt";
else 
    return NULL;
}

void codeBaseType(struct pfCompile *pfc, FILE *f, struct pfBaseType *base)
/* Print out type info for C. */
{
char *s = typeKey(pfc, base);
if (s == NULL)
    fprintf(f, "struct %s*", base->cName);
else
    fprintf(f, "_pf_%s", s);
}

static void codeStackAccess(FILE *f, int offset)
/* Print out code to access stack at offset. */
{
fprintf(f, "%s[%d]", cStackName, offset);
}

static void codeStackFieldAccess(FILE *f, char *field, int offset)
/* Code access to field on stack at offset. */
{
codeStackAccess(f, offset);
fprintf(f, ".%s", field);
}

struct dyString *codeVarName(struct pfCompile *pfc, struct pfVar *var)
/* Return  variable name from C point of view.  (Easy unless it's static). */
{
struct dyString *name = dyStringNew(256);
struct pfType *type = var->ty;
if (type->access == paStatic)
    {
    /* Find enclosing function. */
    struct pfParse *toDec, *classDec;
    char *className = "";
    for (toDec = var->parse; toDec != NULL; toDec = toDec->parent)
	if (toDec->type == pptToDec)
	    break;
    if (toDec == NULL)
        internalErr();
    for (classDec = toDec->parent; classDec!=NULL; classDec = classDec->parent)
	if (toDec->type == pptClass)
	    break;
    if (classDec != NULL)
        className = classDec->name;
    dyStringPrintf(name, "_pf_sta_%d_%s_%s_%s", 
		var->scope->id, className, toDec->name, var->name);
    }
else
    {
    if (var->scope->isLocal)
	{
	if (pfc->codingPara)
	    dyStringAppend(name, "_pf_l->");
	else
	    dyStringAppend(name, "_pf_l.");
	}
    else
	dyStringAppend(name, pfcGlobalPrefix);
    dyStringAppend(name, var->cName);
    }
return name;
}

static void printVarName(struct pfCompile *pfc, FILE *f, struct pfVar *var)
/* Print variable name from C point of view.  (Easy unless it's static). */
{
struct dyString *name = codeVarName(pfc, var);
fprintf(f, "%s", name->string);
dyStringFree(&name);
}

static char *vTypeKey(struct pfCompile *pfc, struct pfBaseType *base)
/* Return typeKey, or "v" is that would be NULL.  The v is used
 * to access void pointer on stack. */
{
char *s = typeKey(pfc, base);
if (s == NULL)
    s = "v";
return s;
}

void codeParamAccess(struct pfCompile *pfc, FILE *f, 
	struct pfBaseType *base, int offset)
/* Print out code to access paramater of given type at offset. */
{
char *s = vTypeKey(pfc, base);
codeStackFieldAccess(f, s, offset);
}

static void rPrintFields(struct pfCompile *pfc, 
	FILE *f, struct pfBaseType *base)
/* Print out fields - parents first */
{
struct pfType *type;
if (base->parent != NULL)
    rPrintFields(pfc, f, base->parent);
for (type = base->fields; type != NULL; type = type->next)
    {
    codeBaseType(pfc, f, type->base);
    fprintf(f, " %s;\n", type->fieldName);
    }
}


static boolean isInitialized(struct pfVar *var)
/* Return TRUE if variable is initialized on declaration in  parse tree. */
{
struct pfParse *pp = var->parse;
if (pp->type != pptVarInit)
    errAt(pp->tok, "Expecting pptVarInit got %s for var %s",
    	pfParseTypeAsString(pp->type), var->name);
return pp->children->next->next != NULL;
}

static void codeMethodName(struct pfCompile *pfc, struct pfToken *tok, 
	FILE *f, struct pfBaseType *base, char *name, int stack)
/* Find method in current class or one of it's parents, and print
 * call to it */
{
if (base == pfc->stringType || base == pfc->dyStringType)
    {
    fprintf(f, "_pf_cm_string_%s", name);
    }
else if (base == pfc->arrayType)
    {
    fprintf(f, "_pf_cm_array_%s", name);
    }
else if (base == pfc->dirType)
    {
    fprintf(f, "_pf_cm_dir_%s", name);
    }
else
    {
    struct pfType *method = NULL;
    while (base != NULL)
	{
	for (method = base->methods; method != NULL; method = method->next)
	    {
	    if (sameString(method->fieldName, name))
		break;
	    }
	if (method != NULL)
	     break;
	base = base->parent;
	}
    if (base != NULL)
	{
	if (base->isClass)
	    {
	    if (method->tyty == tytyVirtualFunction)
		{
		fprintf(f, "%s[%d].Obj->_pf_polyTable[%d]",
		    cStackName, stack, method->polyOffset);
		}
	    else
		fprintf(f, "%s_%s", base->methodPrefix, name);
	    }
	else
	    internalErrAt(tok);
	}
    else
	{
	internalErrAt(tok);
	}
    }
}


static int codeCall(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Generate code for a function call. */
{
struct pfParse *function = pp->children;
struct pfParse *inTuple = function->next;
struct pfType *outTuple = function->ty->children->next;
int outCount = slCount(outTuple->children);
struct pfParse *in;

if (function->type == pptDot)
    {
    struct pfParse *dotList = function->children;
    struct pfParse *class = NULL, *method = NULL;
    struct pfBaseType *base = NULL;
    int dotCount = slCount(dotList);
    assert(dotCount == 2);

    class = dotList;
    method = dotList->next;
    codeExpression(pfc, f, class, stack, FALSE);
    base = class->ty->base;

    /* Put rest of input on the stack, and print call with mangled function name. */
    codeExpression(pfc, f, inTuple, stack+1, TRUE);
    if (base->isInterface)
        {
	fprintf(f, "{\n");
	fprintf(f, "struct %s *_pf_face = %s[%d].v;\n",
		base->cName, cStackName, stack);
	fprintf(f, "%s[%d].v = _pf_face->_pf_obj;\n", cStackName, stack);
	fprintf(f, "_pf_face->%s(%s+%d);\n", method->name, 
		cStackName, stack);
	fprintf(f, "}\n");
	}
    else
	{
	codeMethodName(pfc, pp->tok, f, base, method->name, stack);
	fprintf(f, "(%s+%d);\n", cStackName, stack);
	}
    }
else
    {
    codeExpression(pfc, f, inTuple, stack, TRUE);
    assert(function->type == pptVarUse);
    if (stack == 0)
	fprintf(f, "%s%s(%s);\n", pfcGlobalPrefix, pp->name, cStackName);
    else
	fprintf(f, "%s%s(%s+%d);\n", pfcGlobalPrefix, pp->name, cStackName, stack);
    }
return outCount;
}

static int codeIndirectCall(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Generate code for a function call through a function pointer. */
{
struct pfParse *function = pp->children;
struct pfParse *inTuple = function->next;
struct pfType *outTuple = function->ty->children->next;
int outCount = slCount(outTuple->children);
int paramSize = codeExpression(pfc, f, inTuple, stack, TRUE);
codeExpression(pfc, f, function, stack + paramSize, FALSE);
codeParamAccess(pfc, f, function->ty->base, stack+paramSize);
fprintf(f, "(%s+%d);\n", cStackName, stack);
return outCount;
}


void codeCleanupVarNamed(struct pfCompile *pfc, FILE *f, 
	struct pfType *type, char *name)
/* Emit cleanup code for variable of given type and name. */
{
if (type->base->needsCleanup)
    {
    if (type->base == pfc->varType)
	fprintf(f, "_pf_var_cleanup(%s);\n", name);
    else
	{
	fprintf(f, "if (0!=%s)\n", name);
	fprintf(f, "{\n");
	codeVarDecRef(f, name);
	fprintf(f, "if (%s->_pf_refCount == 0)\n", name);
	fprintf(f, "   %s->_pf_cleanup(%s, ", name, name);
	codeForType(pfc, f, type);
	fprintf(f, ");\n");
	fprintf(f, "}\n");
	}
    }
}

void codeCleanupStackPos(struct pfCompile *pfc, FILE *f,
     struct pfType *type, int stack)
/* Generate cleanup code for stack position. */
{
if (type->base->needsCleanup)
    {
    if (type->base == pfc->varType)
	{
	fprintf(f, "_pf_var_cleanup(");
	codeParamAccess(pfc, f, type->base, stack);
	fprintf(f, ");\n");
	}
    else
        {
	fprintf(f, "if (0!=");
	codeParamAccess(pfc, f, type->base, stack);
	fprintf(f, ")\n");
	fprintf(f, "{\n");
	codeStackDecRef(f, stack);
	fprintf(f, "if (");
	codeParamAccess(pfc, f, type->base, stack);
	fprintf(f, "->_pf_refCount == 0)\n");
	codeParamAccess(pfc, f, type->base, stack);
	fprintf(f, "->_pf_cleanup(");
	codeParamAccess(pfc, f, type->base, stack);
	fprintf(f, ", ");
	codeForType(pfc, f, type);
	fprintf(f, ");\n");
	fprintf(f, "}\n");
	}
    }
}


void codeCleanupVar(struct pfCompile *pfc, FILE *f, 
        struct pfVar *var)
/* Emit cleanup code for variable of given type and name. */
{
struct dyString *name = codeVarName(pfc, var);
codeCleanupVarNamed(pfc, f, var->ty, name->string);
dyStringFree(&name);
}


void codeStartElInCollectionIteration(struct pfCompile *pfc, FILE *f,
	int stack, struct pfScope *scope, struct pfParse *elIxPp, 
	struct pfParse *collectionPp, boolean reverse)
/* This highly technical routine generates some of the code for
 * foreach and para actions.  */
{
struct pfBaseType *base = collectionPp->ty->base;
struct dyString *elName;
struct dyString *keyName = NULL;
struct pfParse *elPp, *ixPp = NULL;

if (elIxPp->type == pptKeyVal)
    {
    ixPp = elIxPp->children;
    elPp = ixPp->next;
    keyName = codeVarName(pfc,ixPp->var);
    assert(base != pfc->indexRangeType);  /* Type checker prevents this */
    }
else
    elPp = elIxPp;

elName = codeVarName(pfc, elPp->var);

if (base == pfc->indexRangeType)
    {
    struct pfParse *fromPp = collectionPp->children;
    struct pfParse *toPp = fromPp->next;
    fprintf(f, "{\n");
    fprintf(f, "{\n");	/* Extra brace so compatible with other collections */
    codeScopeVars(pfc, f, scope, FALSE);
    fprintf(f, "long _pf_offset, _pf_endOffset;\n");
    codeExpression(pfc, f, fromPp, stack, FALSE);
    fprintf(f, "_pf_offset = ");
    codeParamAccess(pfc, f, pfc->longType, stack);
    fprintf(f, ";\n");
    codeExpression(pfc, f, toPp, stack, FALSE);
    fprintf(f, "_pf_endOffset = ");
    codeParamAccess(pfc, f, pfc->longType, stack);
    fprintf(f, ";\n");
    if (reverse)
        fprintf(f, "for (%s=_pf_endOffset-1; %s>=_pf_offset; --%s)\n",
	    elName->string, elName->string, elName->string);
    else
	fprintf(f, "for (%s=_pf_offset; %s<_pf_endOffset; ++%s)\n",
	    elName->string, elName->string, elName->string);
    fprintf(f, "{\n");
    }
else
    {
    /* Get local copy of collection in new scope. */
    fprintf(f, "{\n");
    codeBaseType(pfc, f, collectionPp->ty->base);
    fprintf(f, " _pf_collection;\n");
    codeExpression(pfc, f, collectionPp, stack, FALSE);
    codeNilCheck(f, collectionPp, stack);
    fprintf(f, "_pf_collection = ");
    codeParamAccess(pfc, f, collectionPp->ty->base, stack);
    fprintf(f, ";\n");

    /* Print element variable in a new scope. */
    fprintf(f, "{\n");
    codeScopeVars(pfc, f, scope, TRUE);
    if (base == pfc->arrayType)
	{
	struct pfBaseType *elBase = collectionPp->ty->children->base;
	fprintf(f, "int _pf_offset;\n");
	fprintf(f, "int _pf_elSize = _pf_collection->elSize;\n");
	fprintf(f, "int _pf_endOffset = _pf_collection->size * _pf_elSize;\n");
	if (keyName != NULL)
	    {
	    if (reverse)	/* To help simulate parallelism, do it in reverse. */
		fprintf(f, "for (%s = _pf_collection->size-1, _pf_offset=_pf_endOffset-_pf_elSize; _pf_offset >= 0; %s -= 1, _pf_offset -= _pf_elSize)\n", keyName->string, keyName->string);
	    else
		fprintf(f, "for (%s=0, _pf_offset=0; _pf_offset<_pf_endOffset; _pf_offset += _pf_elSize, %s+=1)\n", keyName->string, keyName->string);
	    }
	else
	    {
	    if (reverse)	/* To help simulate parallelism, do it in reverse. */
		fprintf(f, "for (_pf_offset=_pf_endOffset-_pf_elSize; _pf_offset >= 0; _pf_offset -= _pf_elSize)\n");
	    else
		fprintf(f, "for (_pf_offset=0; _pf_offset<_pf_endOffset; _pf_offset += _pf_elSize)\n");
	    }

	fprintf(f, "{\n");
	fprintf(f, "%s = *((", elName->string);
	codeBaseType(pfc, f, elBase);
	fprintf(f, "*)(_pf_collection->elements + _pf_offset));\n");
	if (elBase->needsCleanup)
	    {
	    fprintf(f, "if (0 != %s) ", elName->string);
	    codeVarIncRef(f, elName->string);
	    }
	}
    else if (base == pfc->stringType || base == pfc->dyStringType)
	{
	char *ixName = "_pf_offset";
	if (keyName != NULL)
	    ixName = keyName->string;
	else
	    fprintf(f, "int %s;\n", ixName);
	fprintf(f, "int _pf_endOffset = _pf_collection->size;\n");
	if (reverse)	/* To help simulate parallelism, do it in reverse. */
	    fprintf(f, "for (%s=_pf_endOffset-1; %s>=0; %s -= 1)\n", ixName, ixName, ixName);
	else
	    fprintf(f, "for (%s=0; %s<_pf_endOffset; %s += 1)\n", ixName, ixName, ixName);
	fprintf(f, "{\n");
	fprintf(f, "%s = _pf_collection->s[%s];\n", elName->string, ixName);
	}
    else if (base == pfc->dirType)
	{
	fprintf(f, "char *_pf_key;\n");
	fprintf(f, 
	    "struct _pf_iterator _pf_ix = _pf_dir_iterator_init(_pf_collection);\n");
	fprintf(f, "while (_pf_ix.next(&_pf_ix, &%s, &_pf_key))\n", elName->string);
	fprintf(f, "{\n");
	if (keyName != NULL)
	    {
	    fprintf(f, "%s = _pf_string_from_const(_pf_key);\n", keyName->string);
	    }
	}
    else
	{
	internalErr();
	}
    }
dyStringFree(&elName);
dyStringFree(&keyName);
}


void codeEndElInCollectionIteration(struct pfCompile *pfc, FILE *f,
	struct pfScope *scope, struct pfParse *elIxPp, 
	struct pfParse *collectionPp, boolean reverse)
/* This highly technical routine generates some of the code for
 * foreach and para actions.  */
{
struct pfBaseType *base = collectionPp->ty->base;
struct dyString *keyName = NULL;
struct pfParse *elPp, *ixPp = NULL;

if (elIxPp->type == pptKeyVal)
    {
    ixPp = elIxPp->children;
    elPp = ixPp->next;
    keyName = codeVarName(pfc,ixPp->var);
    assert(base != pfc->indexRangeType);  /* Type checker prevents this */
    }
else
    elPp = elIxPp;
if (base == pfc->arrayType)
    {
    struct pfBaseType *elBase = collectionPp->ty->children->base;
    if (elBase->needsCleanup)
	{
	struct dyString *elName;
	if (elPp->type == pptKeyVal)
	    elPp = elPp->children->next;
	elName = codeVarName(pfc, elPp->var);
	codeCleanupVarNamed(pfc, f, elPp->var->ty, elName->string);
	dyStringFree(&elName);
	}
    }
else if (base == pfc->dirType)
    {
    if (keyName != NULL)
	{
	codeCleanupVar(pfc, f, ixPp->var);
	}
    }
fprintf(f, "}\n");
if (base == pfc->dirType)
    {
    fprintf(f, "_pf_ix.cleanup(&_pf_ix);\n");
    }
fprintf(f, "}\n");
fprintf(f, "}\n");
}

static void setBestIx(struct pfCompile *pfc, FILE *f,
    struct pfParse *elPp, struct pfBaseType *colBase)
{
fprintf(f, "_pf_best_ix = ");
if (colBase == pfc->dirType)
    fprintf(f, "_pf_key;\n");
else if (colBase == pfc->indexRangeType)
    {
    struct dyString *elName = codeVarName(pfc, elPp->var);
    fprintf(f, " %s;\n", elName->string);
    dyStringFree(&elName);
    }
else if (colBase == pfc->arrayType)
    {
    fprintf(f, " (_pf_offset/_pf_elSize);\n");
    }
else
    {
    internalErr();
    }
}

static void updateArgMinMax(struct pfCompile *pfc, FILE *f,
    struct pfParse *elPp, struct pfBaseType *base, struct pfBaseType *colBase,
    int stack, enum pfParseType paraType)
/* Generate code for paraArgMin/paraArgMax */
{
fprintf(f, "if (");
codeParamAccess(pfc, f, base, stack);
if (paraType == pptParaArgMin)
    fprintf(f, " < ");
else
    fprintf(f, " > ");
fprintf(f, "_pf_acc)\n");
fprintf(f, "{\n");
fprintf(f, "_pf_acc = ");
codeParamAccess(pfc, f, base, stack);
fprintf(f, ";\n");
setBestIx(pfc, f, elPp, colBase);

fprintf(f, "}\n");
}

static int codeParaExpSingle(struct pfCompile *pfc, FILE *f,
	struct pfParse *para, int stack)
/* Generate code for a para expression that just has a single
 * value as a result. */
{
struct pfParse *collectionPp = para->children;
struct pfParse *elPp = collectionPp->next;
struct pfParse *body = elPp->next;
struct pfBaseType *base = para->ty->base;
struct pfBaseType *colBase = collectionPp->ty->base;
boolean isArgType = FALSE;

switch (para->type)
    {
    case pptParaArgMin:
    case pptParaArgMax:
        isArgType = TRUE;
	base = elPp->ty->base;
	break;
    }

fprintf(f, "/* Start %s */\n", pfParseTypeAsString(para->type));
fprintf(f, "{\n");
fprintf(f, "int _pf_first = 1;\n");
codeBaseType(pfc, f, base);
fprintf(f, " _pf_acc = 0;\n");

if (isArgType)
     {
     struct pfBaseType *colBase = collectionPp->ty->base;
     if (colBase == pfc->dirType)
	 fprintf(f, "char *_pf_best_ix = 0;\n");
     else
	 fprintf(f, "long _pf_best_ix = -1;\n");
     }

codeStartElInCollectionIteration(pfc, f, stack, 
	para->scope, elPp, collectionPp, TRUE);

/* Calculate expression */
codeExpression(pfc, f, body, stack, FALSE);

/* In all cases first time through we just initialize accumalator with
 * expression value. */
fprintf(f, "if (_pf_first)\n");
fprintf(f, "{\n");
fprintf(f, "_pf_first = 0;\n");
fprintf(f, "_pf_acc = ");
codeParamAccess(pfc, f,base, stack);
fprintf(f, ";\n");
if (isArgType)
    setBestIx(pfc, f, elPp, colBase);
fprintf(f, "}\n");

/* What we do rest of time depends on the type of para. */
fprintf(f, "else\n");
fprintf(f, "{\n");
switch (para->type)
    {
    case pptParaMin:
	 fprintf(f, "if (");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, " < _pf_acc) _pf_acc = ");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, ";\n");
         break;
    case pptParaMax:
	 fprintf(f, "if (");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, " > _pf_acc) _pf_acc = ");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, ";\n");
         break;
    case pptParaArgMin:
    case pptParaArgMax:
	 updateArgMinMax(pfc, f, elPp, base, colBase, stack, para->type);
	 break;
    case pptParaAdd:
	 fprintf(f, "_pf_acc += ");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, ";\n");
         break;
    case pptParaMultiply:
	 fprintf(f, "_pf_acc *= ");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, ";\n");
         break;
    case pptParaAnd:
         fprintf(f, "_pf_acc &= ");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, ";\n");
	 break;
    case pptParaOr:
         fprintf(f, "_pf_acc |= ");
	 codeParamAccess(pfc, f, base, stack);
	 fprintf(f, ";\n");
	 break;
    default:
        internalErr();
	break;
    }
fprintf(f, "}\n");

codeEndElInCollectionIteration(pfc, f, para->scope, elPp, collectionPp, TRUE);

codeParamAccess(pfc, f, para->ty->base, stack);
if (isArgType)
     {
     struct pfBaseType *colBase = collectionPp->ty->base;
     if (colBase == pfc->dirType)
	 fprintf(f, " = _pf_string_from_const(_pf_best_ix);\n");
     else
	 fprintf(f, " = _pf_best_ix;\n");
     }
else
    {
    fprintf(f, " = _pf_acc;\n");
    }
fprintf(f, "}\n");
fprintf(f, "/* End %s */\n", pfParseTypeAsString(para->type));

return 1;
}

static void codeRangeIntoStartEndSize(struct pfCompile *pfc,
	FILE *f, struct pfParse *indexRange, int stack)
/* Generate code to created _pf_start/_pf_end/_pf_size variables
 * with values filled in */
{
struct pfParse *startPp = indexRange->children;
struct pfParse *endPp = startPp->next;
fprintf(f, "long _pf_start, _pf_end, _pf_size;\n");
fprintf(f, "_pf_Array _pf_result;\n");
codeExpression(pfc, f, startPp, stack, FALSE);
fprintf(f, "_pf_start = %s[%d].Long;\n", cStackName, stack);
codeExpression(pfc, f, endPp, stack, FALSE);
fprintf(f, "_pf_end = %s[%d].Long;\n", cStackName, stack);
fprintf(f, "_pf_size = _pf_end - _pf_start;\n");
fprintf(f, "if (_pf_size <= 0)\n");
codeRunTimeError(f, indexRange, "no items in range");
}

static int codeParaGet(struct pfCompile *pfc, FILE *f,
	struct pfParse *para, int stack)
/* Generate code for a para get expression */
{
struct pfParse *collection = para->children;
struct pfParse *element = collection->next;
struct pfParse *expression = element->next;
struct pfBaseType *collectBase = collection->ty->base;

fprintf(f, "/* start para get */\n");
fprintf(f, "{\n");

if (collectBase == pfc->arrayType || collectBase == pfc->indexRangeType)
    {
    fprintf(f, "int _pf_resElSize, _pf_resOffset = 0;\n");
    if (collectBase == pfc->arrayType)
	{
	fprintf(f, "_pf_Array _pf_coll, _pf_result;\n");
	codeExpression(pfc, f, collection, stack, FALSE);
	fprintf(f, "_pf_coll = ");
	codeParamAccess(pfc, f, collectBase, stack);
	fprintf(f, ";\n");
	fprintf(f, "_pf_result = _pf_dim_array(_pf_coll->size, ");
	codeForType(pfc, f, expression->ty);
	fprintf(f, ");\n");
	}
    else
	{
	codeRangeIntoStartEndSize(pfc, f, collection, stack);
	fprintf(f, "_pf_result = _pf_dim_array(_pf_size, ");
	codeForType(pfc, f, expression->ty);
	fprintf(f, ");\n");
	}
    fprintf(f, "_pf_resElSize = _pf_result->elSize;\n");
    codeStartElInCollectionIteration(pfc, f, stack, para->scope, element, 
    	collection, FALSE);
    codeExpression(pfc, f, expression, stack, TRUE);
    fprintf(f, "*((");
    codeBaseType(pfc, f, expression->ty->base);
    fprintf(f, "*)(_pf_result->elements + _pf_resOffset)) = ");
    codeParamAccess(pfc, f, expression->ty->base, stack);
    fprintf(f, ";\n");
    fprintf(f, "_pf_resOffset += _pf_resElSize;\n");
    codeEndElInCollectionIteration(pfc, f, para->scope, element, 
    	collection, FALSE);
    }
else if (collectBase == pfc->dirType)
    {
    fprintf(f, "_pf_Dir _pf_coll, _pf_result;\n");
    codeExpression(pfc, f, collection, stack, FALSE);
    fprintf(f, "_pf_coll = ");
    codeParamAccess(pfc, f, collectBase, stack);
    fprintf(f, ";\n");
    fprintf(f, "_pf_result = _pf_dir_new(_pf_dir_size(_pf_coll), ");
    codeForType(pfc, f, expression->ty);
    fprintf(f, ");\n");

    codeStartElInCollectionIteration(pfc, f, stack, para->scope, element, 
    	collection, FALSE);
    codeExpression(pfc, f, expression, stack, TRUE);
    if (expression->ty->base->needsCleanup)
	{
	fprintf(f, "_pf_dir_add_obj(_pf_result, _pf_key, %s+%d);\n",  
		cStackName, stack);
	}
    else 
	{
	fprintf(f, "_pf_dir_add_num(_pf_result, _pf_key, %s+%d);\n",  
		cStackName, stack);
	}
    codeEndElInCollectionIteration(pfc, f, para->scope, element, 
    	collection, FALSE);
    }
else
    {
    internalErr();
    }


codeParamAccess(pfc, f, collectBase, stack);
fprintf(f, " = _pf_result;\n");
fprintf(f, "}\n");
fprintf(f, "/* end para get */\n");
return 1;
}

static int codeParaFilter(struct pfCompile *pfc, FILE *f,
	struct pfParse *para, int stack)
/* Generate code for a para filter expression */
{
struct pfParse *collection = para->children;
struct pfParse *element = collection->next;
struct pfParse *expression = element->next;
struct pfBaseType *collectBase = collection->ty->base;
struct dyString *elName = codeVarName(pfc, element->var);

fprintf(f, "/* start para filter */\n");
fprintf(f, "{\n");
if (collectBase == pfc->arrayType || collectBase == pfc->indexRangeType)
    {
    /* Generate code that will create an array of chars
     * filled with 1's where filter is passed, and 0's elsewhere. */
    fprintf(f, "int _pf_ix=0,_pf_passCount=0,_pf_passOne,_pf_resOffset=0;\n");
    fprintf(f, "char *_pf_passed;\n");
    if (collectBase == pfc->arrayType)
	{
	fprintf(f, "_pf_Array _pf_result;\n");
	fprintf(f, "_pf_Array _pf_coll;\n");
	codeExpression(pfc, f, collection, stack, FALSE);
	fprintf(f, "_pf_coll = ");
	codeParamAccess(pfc, f, collectBase, stack);
	fprintf(f, ";\n");
	fprintf(f, "_pf_passed = _pf_need_mem(_pf_coll->size);\n");
	}
    else
        {
	fprintf(f, "int _pf_elSize = sizeof(_pf_Long);\n");
	codeRangeIntoStartEndSize(pfc, f, collection, stack);
	fprintf(f, "_pf_passed = _pf_need_mem(_pf_size);\n");
	}

    codeStartElInCollectionIteration(pfc, f, stack, para->scope, element, 
    	collection, FALSE);
    codeExpression(pfc, f, expression, stack, FALSE);
    fprintf(f, "_pf_passOne = ");
    codeParamAccess(pfc, f, pfc->bitType, stack);
    fprintf(f, ";\n");
    fprintf(f, "_pf_passed[_pf_ix++] = _pf_passOne;\n");
    fprintf(f, "_pf_passCount += _pf_passOne;\n");
    codeEndElInCollectionIteration(pfc, f, para->scope, element, 
    	collection, FALSE);

    /* Allocate results array. */
    fprintf(f, "_pf_result = _pf_dim_array(_pf_passCount, ");
    if (collectBase == pfc->arrayType)
	codeForType(pfc, f, collection->ty->children);
    else
        codeForType(pfc, f, pfc->longFullType);
    fprintf(f, ");\n");

    /* Generate code that will copy passing elements to results */
    fprintf(f, "_pf_passCount = 0;\n");
    fprintf(f, "_pf_ix = 0;\n");
    codeStartElInCollectionIteration(pfc, f, stack, para->scope, element, 
    	collection, FALSE);
    fprintf(f, "if (_pf_passed[_pf_ix++])\n");
    fprintf(f, "{\n");
    if (element->ty->base->needsCleanup)
	codeVarIncRef(f, elName->string);
    fprintf(f, "*((");
    codeBaseType(pfc, f, element->ty->base);
    fprintf(f, "*)(_pf_result->elements + _pf_resOffset))");
    fprintf(f, "=%s;\n", elName->string);
    fprintf(f, "_pf_resOffset += _pf_elSize;\n");
    fprintf(f, "}\n");
    codeEndElInCollectionIteration(pfc, f, para->scope, element, 
    	collection, FALSE);

    /* Generate clean up code. */
    fprintf(f, "_pf_free_mem(_pf_passed);\n");
    }
else if (collectBase == pfc->dirType)
    {
    struct pfType *elType = element->ty;
    fprintf(f, "_pf_Dir _pf_coll, _pf_result;\n");
    codeExpression(pfc, f, collection, stack, FALSE);
    fprintf(f, "_pf_coll = ");
    codeParamAccess(pfc, f, collectBase, stack);
    fprintf(f, ";\n");
    fprintf(f, "_pf_result = _pf_dir_new(_pf_dir_size(_pf_coll), ");
    codeForType(pfc, f, elType);
    fprintf(f, ");\n");

    codeStartElInCollectionIteration(pfc, f, stack, para->scope, element, 
    	collection, FALSE);
    codeExpression(pfc, f, expression, stack, TRUE);
    fprintf(f, "if (");
    codeParamAccess(pfc, f, pfc->bitType, stack);
    fprintf(f, ")\n");
    fprintf(f, "{\n");
    codeParamAccess(pfc, f, elType->base, stack);
    fprintf(f, "=%s;\n", elName->string);
    if (elType->base->needsCleanup)
	{
	codeVarIncRef(f, elName->string);
	fprintf(f, "_pf_dir_add_obj(_pf_result, _pf_key, %s+%d);\n",  
		cStackName, stack);
	}
    else 
	{
	fprintf(f, "_pf_dir_add_num(_pf_result, _pf_key, %s+%d);\n",  
		cStackName, stack);
	}
    fprintf(f, "}\n");

    codeEndElInCollectionIteration(pfc, f, para->scope, element, 
    	collection, FALSE);
    }
else
    internalErr();
codeParamAccess(pfc, f, collectBase, stack);
fprintf(f, " = _pf_result;\n");
fprintf(f, "}\n");
fprintf(f, "/* end para filter */\n");
dyStringFree(&elName);
return 1;
}

static void startCleanTemp(FILE *f)
/* Declare a temp variable to assist in cleanup */
{
fprintf(f, " {\n struct _pf_object *_pf_tmp = (struct _pf_object *)\n  ");
}

static void endCleanTemp(struct pfCompile *pfc, FILE *f, struct pfType *type)
{
fprintf(f, ";\n");
fprintf(f, " if (_pf_tmp != 0)\n");
fprintf(f, "{\n");
codeVarDecRef(f, "_pf_tmp");
fprintf(f, "if (_pf_tmp->_pf_refCount == 0)\n");
fprintf(f, "   _pf_tmp->_pf_cleanup(_pf_tmp, ");
codeForType(pfc, f, type);
fprintf(f, ");\n");
fprintf(f, "}\n");
fprintf(f, " }\n");
}

static void bumpStackRefCount(struct pfCompile *pfc,
	FILE *f, struct pfType *type, int stack)
/* If type is reference counted, bump up refCount of top of stack. */
{
struct pfBaseType *base = type->base;

if (base == pfc->varType)
    {
    fprintf(f, "_pf_var_link(");
    codeStackAccess(f, stack);
    fprintf(f, ".Var");
    fprintf(f, ");\n");
    }
else if (base->needsCleanup)
    {
    fprintf(f, "if (0 != ");
    codeStackAccess(f, stack);
    fprintf(f, ".Obj) ");
    codeStackIncRef(f, stack);
    }
}

static int pushArrayIndexAndBoundsCheck(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Put collection and index on stack.  Check index is in range. 
 * Return offset to index. */
{
struct pfType *outType = pp->ty;
struct pfParse *collection = pp->children;
struct pfBaseType *colBase = collection->ty->base;
struct pfParse *index = collection->next;

/* Push array and index onto expression stack */
int offset = codeExpression(pfc, f, collection, stack, FALSE);
codeNilCheck(f, collection, stack);
codeExpression(pfc, f, index, stack+offset, FALSE);

/* Do bounds checking */
fprintf(f, "if (");
codeParamAccess(pfc, f, pfc->intType, stack+offset);
fprintf(f, "< 0 || ");
codeParamAccess(pfc, f, pfc->intType, stack+offset);
fprintf(f, " >= ");
codeParamAccess(pfc, f, colBase, stack);
fprintf(f, "->size)\n  ");
codeRunTimeError(f, pp, "array access out of bounds");
return offset;
}

static void codeArrayAccess(struct pfCompile *pfc, FILE *f,
	struct pfBaseType *base, int stack, int indexOffset)
/* Print out code to access array (on either left or right
 * side */
{
fprintf(f, "((");
codeBaseType(pfc, f, base);
fprintf(f, "*)(");
codeParamAccess(pfc, f, pfc->arrayType, stack);
fprintf(f, "->elements + %d * ",  base->size);
codeParamAccess(pfc, f, pfc->intType, stack+indexOffset);
fprintf(f, "))[0]");
}

static void codeAccessToByteInString(struct pfCompile *pfc, FILE *f,
	struct pfBaseType *base, int stack, int indexOffset)
/* Print out code to a byte in string. */
{
codeParamAccess(pfc, f, pfc->stringType, stack);
fprintf(f, "->s[");
codeParamAccess(pfc, f, pfc->intType, stack+indexOffset);
fprintf(f, "]");
}


static int codeIndexRval(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, boolean addRef)
/* Generate code for index expression (not on left side of
 * assignment */
{
struct pfType *outType = pp->ty;
struct pfParse *collection = pp->children;
struct pfParse *index = collection->next;
struct pfBaseType *colBase = collection->ty->base;
if (colBase == pfc->arrayType)
    {
    int indexOffset = pushArrayIndexAndBoundsCheck(pfc, f, pp, stack);
    codeParamAccess(pfc, f, outType->base, stack);
    fprintf(f, " = ");
    codeArrayAccess(pfc, f, outType->base, stack, indexOffset);
    fprintf(f, ";\n");
    if (addRef) 
    	bumpStackRefCount(pfc, f, outType, stack);
    }
else if (colBase == pfc->stringType || colBase == pfc->dyStringType)
    {
    int indexOffset = pushArrayIndexAndBoundsCheck(pfc, f, pp, stack);
    codeParamAccess(pfc, f, outType->base, stack);
    fprintf(f, " = ");
    codeAccessToByteInString(pfc, f, outType->base, stack, indexOffset);
    fprintf(f, ";\n");
    }
else if (colBase == pfc->dirType)
    {
    int offset = codeExpression(pfc, f, collection, stack, FALSE);
    codeExpression(pfc, f, index, stack+offset, FALSE);
    if (outType->base->needsCleanup)
	{
	fprintf(f, "%s[%d].Obj", cStackName, stack);
	fprintf(f, " = ");
        fprintf(f, "_pf_dir_lookup_object(%s+%d, %d);\n", cStackName, stack,
		addRef);
	}
    else 
	{
	fprintf(f, "_pf_dir_lookup_number(%s+%d);\n",  cStackName, stack);
	}
    }
else
    {
    internalErr();
    }
return 1;
}

static void codeIndexLval(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, char *op, int expSize, 
	boolean cleanupOldVal)
/* Generate code for index expression  on left side of assignment */
{
struct pfType *outType = pp->ty;
struct pfParse *collection = pp->children;
struct pfParse *index = collection->next;
struct pfBaseType *colBase = collection->ty->base;
int emptyStack = stack + expSize;
if (colBase == pfc->arrayType)
    {
    int indexOffset = pushArrayIndexAndBoundsCheck(pfc, f, pp, emptyStack);
    if (outType->base == pfc->varType)
        {
	fprintf(f, "_pf_var_cleanup(");
	codeArrayAccess(pfc, f, outType->base, emptyStack, indexOffset);
	fprintf(f, ");\n");
	}
    else if (outType->base->needsCleanup)
        {
	startCleanTemp(f);
	codeArrayAccess(pfc, f, outType->base, emptyStack, indexOffset);
	endCleanTemp(pfc, f, outType);
	}
    codeArrayAccess(pfc, f, outType->base, emptyStack, indexOffset);
    fprintf(f, " %s ", op);
    codeParamAccess(pfc, f, outType->base, stack);
    fprintf(f, ";\n");
    }
else if (colBase == pfc->dyStringType)
    {
    int indexOffset = pushArrayIndexAndBoundsCheck(pfc, f, pp, emptyStack);
    codeAccessToByteInString(pfc, f, outType->base, emptyStack, indexOffset);
    fprintf(f, " %s ", op);
    codeParamAccess(pfc, f, outType->base, stack);
    fprintf(f, ";\n");
    }
else if (colBase == pfc->stringType)
    {
    internalErr();  /* Type checker prevents this. */
    }
else if (colBase == pfc->dirType)
    {
    int offset = codeExpression(pfc, f, collection, emptyStack, FALSE);
    codeExpression(pfc, f, index, emptyStack+offset, FALSE);
    if (outType->base->needsCleanup)
	{
        fprintf(f, "_pf_dir_add_object(%s+%d, %d);\n", cStackName, stack, expSize);
	}
    else 
	{
	/* We're doing something like:
	 *     wordCount['the'] += 1;
	 * or more abstractly:
	 *     collection[index] op expression;
	 * The stack currently contains:
	 *     expression collection index. */
	if (!sameString(op, "="))
	    {
	    fprintf(f, "_pf_dir_lookup_number(%s+%d);\n", cStackName, 
	    	emptyStack);
	    codeParamAccess(pfc, f, outType->base, stack);
	    fprintf(f, " %s ", op);
	    codeParamAccess(pfc, f, outType->base, emptyStack);
	    fprintf(f, ";\n");
	    offset = codeExpression(pfc, f, collection, emptyStack, FALSE);
	    codeExpression(pfc, f, index, emptyStack+offset, FALSE);
	    }
	fprintf(f, "_pf_dir_add_number(%s+%d, %d);\n",  cStackName, stack, expSize);
	}
    }
else
    {
    internalErr();
    }
}

static void codeDotAccess(struct pfCompile *pfc, FILE *f, 
	struct pfParse *pp, int stack)
/* Print out code to access field (on either left or right
 * side */
{
struct pfParse *class = pp->children;
struct pfParse *field = class->next;
struct pfBaseType *base = class->ty->base;
if (base == pfc->stringType || base == pfc->dyStringType || base == pfc->arrayType)
    fprintf(f, "(");
else
    fprintf(f, "((struct %s *)", base->cName);
codeParamAccess(pfc, f, base, stack);
fprintf(f, ")");
assert(field->next == NULL);
fprintf(f, "->%s", field->name);
field = field->next;
}
	

static int codeDotRval(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Generate code for . expression (not on left side of
 * assignment */
{
struct pfType *outType = pp->ty;
struct pfParse *class = pp->children;
codeExpression(pfc, f, class, stack, FALSE);
codeNilCheck(f, class, stack);
codeParamAccess(pfc, f, outType->base, stack);
fprintf(f, " = ");
codeDotAccess(pfc, f, pp, stack);
fprintf(f, ";\n");
bumpStackRefCount(pfc, f, outType, stack);
return 1;
}


static void codeDotLval(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, char *op, int expSize, 
	boolean cleanupOldVal)
/* Generate code for dot expression  on left side of assignment */
{
struct pfType *outType = pp->ty;
struct pfParse *class = pp->children;
struct pfParse *field = class->next;
int emptyStack = stack + expSize;
codeExpression(pfc, f, class, emptyStack, FALSE);
codeNilCheck(f, class, emptyStack);
if (outType->base->needsCleanup)
    {
    startCleanTemp(f);
    codeDotAccess(pfc, f, pp, emptyStack);
    endCleanTemp(pfc, f, outType);
    }
codeDotAccess(pfc, f, pp, emptyStack);
fprintf(f, " %s ", op);
codeParamAccess(pfc, f, outType->base, stack);
fprintf(f, ";\n");
}

static void codeZeroInitOfType(struct pfCompile *pfc, FILE *f, struct pfType *type)
/* Print out default initialization of type. */
{
if (type->base == pfc->varType)
    fprintf(f, "=_pf_var_zero");
else
    fprintf(f, "=0");
}

static void codeVarsInHelList(struct pfCompile *pfc, FILE *f,
	struct hashEl *helList, boolean zeroUninit, boolean isModuleScope)
/* Print out variable declarations in helList. */
{
struct hashEl *hel;
boolean gotVar = FALSE;
for (hel = helList; hel != NULL; hel = hel->next)
    {
    struct pfVar *var = hel->val;
    struct pfType *type = var->ty;
    if ((type->tyty == tytyVariable || type->tyty == tytyFunctionPointer)
	&& type->access != paStatic)
	{
	if (var->isExternal)
	    fprintf(f, "extern ");
	if (pfc->isFunc)
	    {
	    if (zeroUninit && !var->isExternal && !isInitialized(var))
		{
		printVarName(pfc, f, var);
		codeZeroInitOfType(pfc, f, type);
		fprintf(f, ";\n");
		}
	    }
	else
	    {
	    enum pfAccessType access = var->ty->access;
	    if (access != paGlobal && access != paWritable && isModuleScope)
	         fprintf(f, "static ");
	    codeBaseType(pfc, f, type->base);
	    fprintf(f, " ");
	    printVarName(pfc, f, var);
	    if (zeroUninit && !var->isExternal && !isInitialized(var))
		{
		codeZeroInitOfType(pfc, f, type);
		}
	    fprintf(f, ";\n");
	    }
	gotVar = TRUE;
	}
    }
}

static void codeCleanupVarsInHelList(struct pfCompile *pfc, FILE *f,
	struct hashEl *helList)
/* Print out variable cleanups for helList. */
{
struct hashEl *hel;
for (hel = helList; hel != NULL; hel = hel->next)
    {
    struct pfVar *var = hel->val;
    if (!var->isExternal && var->ty->access != paStatic)
	codeCleanupVar(pfc, f, var);
    }
}

void codeScopeVars(struct pfCompile *pfc, FILE *f, struct pfScope *scope,
	boolean zeroUninitialized)
/* Print out variable declarations associated with scope. */
{
struct hashEl *helList = hashElListHash(scope->vars);
slSort(&helList, hashElCmp);
codeVarsInHelList(pfc, f, helList, zeroUninitialized, FALSE);
hashElFreeList(&helList);
}

static void cleanupScopeVars(struct pfCompile *pfc, FILE *f, 
	struct pfScope *scope)
/* Print out variable declarations associated with scope. */
{
struct hashEl *helList = hashElListHash(scope->vars);
slSort(&helList, hashElCmp);
slReverse(&helList);
codeCleanupVarsInHelList(pfc, f, helList);
hashElFreeList(&helList);
}



static int lvalOffStack(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, char *op, int expSize,
	boolean cleanupOldVal)
/* Take an lval off of stack. */
{
switch (pp->type)
    {
    case pptVarUse:
    case pptVarInit:
	{
	struct pfBaseType *base = pp->ty->base;
	if (cleanupOldVal && base->needsCleanup)
	    codeCleanupVar(pfc, f, pp->var);
	printVarName(pfc, f, pp->var);
	fprintf(f, " %s ", op);
	codeParamAccess(pfc, f, base, stack);
	fprintf(f, ";\n");
	return 1;
	}
    case pptTuple:
        {
	int total = 0;
	struct pfParse *p;
	for (p = pp->children; p != NULL; p = p->next)
            {
	    total += lvalOffStack(pfc, f, p, stack+total, op, expSize-total,
	    	cleanupOldVal);
	    }
	return total;
	}
    case pptIndex:
        {
	codeIndexLval(pfc, f, pp, stack, op, expSize, cleanupOldVal);
	return 1;
	}
    case pptDot:
        {
	codeDotLval(pfc, f, pp, stack, op, expSize, cleanupOldVal);
	return 1;
	}
    default:
        fprintf(f, "using %s %s as an lval\n", pp->name, pfParseTypeAsString(pp->type));
	internalErr();
	return 0;
    }
}

static void rCodeTupleType(struct pfCompile *pfc, FILE *f, struct pfType *type)
/* Recursively encode tuple type to output. */
{
struct pfType *t;
fprintf(f, "(");
for (t = type->children; t != NULL; t = t->next)
    {
    struct pfType *tk = t;
    if (t->base == pfc->keyValType)
        tk = t->children->next;
    if (tk->tyty == tytyTuple)
        rCodeTupleType(pfc, f, tk);
    else
        fprintf(f, "x");
    }
fprintf(f, ")");
}

static void codeTupleIntoCollection(struct pfCompile *pfc, FILE *f,
	struct pfType *type, struct pfParse *rval, int stack, int tupleSize)
/* Shovel tuple into array, list, dir, tree. */
{
struct pfBaseType *base = type->base;
codeParamAccess(pfc, f, base, stack);
fprintf(f, " = ");
if (base == pfc->arrayType // ||  base == pfc->listType || base == pfc->treeType
	|| base == pfc->dirType)
    {
    struct pfBaseType *base = type->children->base;
    if (base == pfc->bitType || base == pfc->byteType || base == pfc->shortType
	|| base == pfc->intType || base == pfc->longType || base == pfc->floatType
	|| base == pfc->doubleType || base == pfc->charType 
	|| base == pfc->stringType  || base == pfc->dyStringType
	|| base == pfc->varType)
	{
	fprintf(f, "_pf_%s_%s_from_tuple(%s+%d, %d, ",
		base->name, type->base->name, cStackName, stack, tupleSize);
	codeForType(pfc, f, type), 
	fprintf(f, ", ");
	codeForType(pfc, f, type->children);
	fprintf(f, ");\n");
	}
    else
	{
	fprintf(f, "_pf_tuple_to_%s(%s+%d, ", type->base->name,
		cStackName, stack);
	codeForType(pfc, f, type->children);
	fprintf(f, ", \"");
	rCodeTupleType(pfc, f, rval->ty);
	fprintf(f, "\");\n");
	}
    }
else
    {
    internalErr();
    }
}

static void codeTupleIntoClass(struct pfCompile *pfc, FILE *f,
	struct pfParse *typePp, struct pfParse *tuplePp, 
	int stack, int tupleSize)
/* Shovel tuple into class. */
{
// TODO - add this to function call as well? 
struct pfBaseType *base = typePp->ty->base;
codeParamAccess(pfc, f, base, stack);
fprintf(f, " = ");
fprintf(f, "_pf_tuple_to_class(%s+%d, ",
	cStackName, stack);
codeForType(pfc, f, typePp->ty);
fprintf(f, ", \"");
rCodeTupleType(pfc, f, tuplePp->ty);
fprintf(f, "\");\n");
}

static int codeInitOrAssign(struct pfCompile *pfc, FILE *f,
	struct pfParse *lval, struct pfParse *rval,
	int stack)
/* Emit code for initialization or assignment. */
{
int count = codeExpression(pfc, f, rval, stack, TRUE);
if (rval->type == pptUniformTuple)
    codeTupleIntoCollection(pfc, f, lval->ty, rval, stack, count);
if (lval->type == pptTuple)
    return slCount(lval->children);
else
    return 1;
}

static void cantCopeParamType(struct pfParse *pp, int code)
/* Explain that can't deal with parameterized type complications.
 * Hopefully this is temporary. */
{
errAt(pp->tok, "Don't know how to deal with this parameterized type (code %d)", 
	code);
}

static boolean isArraysOnAcross(struct pfCompile *pfc, struct pfParse *ppOf)
/* Chase children of a pptOf node.  If these are all pptTypeNames,
 * and all but the last is base type array, then return TRUE. */
{
struct pfParse *type;
for (type = ppOf->children; type != NULL; type = type->next)
    {
    if (type->next == NULL)
	break;
    if (type->ty->base != pfc->arrayType)
        return FALSE;
    }
return TRUE;
}

static boolean checkIfNeedsDims(struct pfCompile *pfc, struct pfParse *type)
/* Return TRUE if it looks like we need to generate initialzation code 
 * for an array even if it isn't assigned anything. */
{
if (type->type != pptOf)
    return FALSE;
if (type->children == NULL)
    internalErr();
if (type->children->children == NULL)
    return FALSE;
if (!isArraysOnAcross(pfc, type))
    errAt(type->tok, "Sorry right now you can only parameterize arrays");
return TRUE;
}


static void codeInitDims(struct pfCompile *pfc, FILE *f, struct pfParse *pp, int stack)
/* Generate code that creates an array that is initialized to
 * zero (as opposed to the empty array). */
{
struct pfParse *ppOf = pp->children;
struct pfParse *sym = ppOf->next;
int dimCount = slCount(ppOf->children) - 1;
if (dimCount == 1)
    {
    struct pfParse *type = ppOf->children;
    codeExpression(pfc, f, type->children, stack, FALSE);
    fprintf(f, "%s[%d].Array = ", cStackName, stack);
    fprintf(f, "_pf_dim_array(%s[%d].Long, ", cStackName, stack);
    codeForType(pfc, f, type->next->ty);
    fprintf(f, ");\n");
    lvalOffStack(pfc, f, pp, stack, "=", 1, FALSE);
    }
else
    {
    int offset = 0;
    int inittedDims = 0;
    struct pfParse *type;
    for (type = ppOf->children; type != NULL; type = type->next)
        {
	if (type->next == NULL || type->children == NULL)
	    {
	    /* Final type - contains type of array cell.  Output call. */
	    fprintf(f, "%s[%d].Array = ", cStackName, stack);
	    fprintf(f, "_pf_multi_dim_array(%s+%d, %d, ", 
	    	cStackName, stack, inittedDims);
	    codeForType(pfc, f, ppOf->ty);
	    fprintf(f, ");\n");
	    lvalOffStack(pfc, f, pp, stack, "=", 1, FALSE);
	    break;
	    }
	else
	    {
	    offset += codeExpression(pfc, f, type->children, stack+offset, FALSE);
	    inittedDims += 1;
	    }
	}
    }
}

static int codeAllocInit(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Generate code to allocate memory and initialize a class
 * first by default values in tuple, and then by init method. */
{
struct pfParse *defaultTuple = pp->children;
struct pfParse *initTuple = defaultTuple->next;
struct pfBaseType *base = pp->ty->base;
int offset = codeExpression(pfc, f, defaultTuple, stack, TRUE);
fprintf(f, "{\n");
fprintf(f, "struct _pf_object *_pf_obj = ");
fprintf(f, "_pf_tuple_to_class(%s+%d, ", cStackName, stack);
codeForType(pfc, f, pp->ty);
fprintf(f, ", \"");
rCodeTupleType(pfc, f, defaultTuple->ty);
fprintf(f, "\");\n");
fprintf(f, "%s[%d].Obj = _pf_obj;\n", cStackName, stack);
codeExpression(pfc, f, initTuple, stack+1, TRUE);
codeMethodName(pfc, pp->tok, f, base, "init", stack);
fprintf(f, "(%s+%d);\n", cStackName, stack);
fprintf(f, "%s[%d].Obj = _pf_obj;\n", cStackName, stack);
fprintf(f, "}\n");
return 1;
}

static int codeNewOp(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Generate code for new operator. */
{
struct pfParse *typePp = pp->children;
struct pfParse *initPp = typePp->next;
return codeExpression(pfc, f, initPp, stack, TRUE);
}

static void codeVarInit(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Generate code for an assignment. */
{
struct pfParse *lval = pp;
struct pfParse *type = pp->children;
struct pfParse *name = type->next;
struct pfParse *rval = name->next;
boolean gotDims = checkIfNeedsDims(pfc, type);
if (rval != NULL)
    {
    int count = codeInitOrAssign(pfc, f, lval, rval, stack);
    lvalOffStack(pfc, f, lval, stack, "=", count, FALSE);
    }
else if (gotDims)
    codeInitDims(pfc, f, pp, stack);
}

static int codeAssignment(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, char *op)
/* Generate code for an assignment. */
{
struct pfParse *lval = pp->children;
struct pfParse *rval = lval->next;

if (lval->type == pptTuple && rval->type == pptTuple)
    {
    for (lval = lval->children, rval = rval->children; 
    	lval != NULL; lval = lval->next, rval = rval->next)
        {
	int count = codeInitOrAssign(pfc, f, lval, rval, stack);
	lvalOffStack(pfc, f, lval, stack, op, count, TRUE);
	}
    }
else
    {
    int count = codeInitOrAssign(pfc, f, lval, rval, stack);
    lvalOffStack(pfc, f, lval, stack, op, count, TRUE);
    }
return 0;
}

static int codeVarUse(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, boolean addRef)
/* Generate code for moving a variable onto stack. */
{
struct pfBaseType *base = pp->ty->base;
struct dyString *name = codeVarName(pfc, pp->var);
if (addRef && base->needsCleanup)
    {
    if (base == pfc->varType)
	fprintf(f, "_pf_var_link(%s);\n", name->string);
    else
	{
	fprintf(f, "if (0 != %s) ", name->string);
	codeVarIncRef(f, name->string);
	}
    }
codeParamAccess(pfc, f, base, stack);
fprintf(f, " = %s;\n", name->string);
dyStringFree(&name);
return 1;
}
	
static int codeBinaryOp(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, char *op)
/* Emit code for some sort of binary op. */
{
struct pfParse *lval = pp->children;
struct pfParse *rval = lval->next;
codeExpression(pfc, f, lval, stack, TRUE);
codeExpression(pfc, f, rval, stack+1, TRUE);
codeParamAccess(pfc, f, pp->ty->base, stack);
fprintf(f, " = ");
if (lval->ty->base == pfc->stringType || lval->ty->base == pfc->dyStringType)
    {
    fprintf(f, " (_pf_strcmp(%s+%d) %s 0);\n", cStackName, stack, op);
    }
else
    {
    codeParamAccess(pfc, f, lval->ty->base, stack);
    fprintf(f, " %s ", op);
    codeParamAccess(pfc, f, rval->ty->base, stack+1);
    fprintf(f, ";\n");
    }
return 1;
}

static int codeUnaryOp(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, char *op)
/* Emit code for some sort of unary op. */
{
struct pfParse *child = pp->children;
struct pfBaseType *base = child->ty->base;
codeExpression(pfc, f, child, stack, TRUE);
codeParamAccess(pfc, f, base, stack);
fprintf(f, " = ");
fprintf(f, "%s", op);
codeParamAccess(pfc, f, base, stack);
fprintf(f, ";\n");
return 1;
}

static int codeStringCat(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, boolean addRef)
/* Generate code for a string concatenation. */
{
int total = 0;
struct pfParse *p;
for (p = pp->children; p != NULL; p = p->next)
    total += codeExpression(pfc, f, p, stack+total, addRef);
codeParamAccess(pfc, f, pp->ty->base, stack);
fprintf(f, " = ");
fprintf(f, "_pf_string_cat(%s+%d, %d);\n", cStackName, stack, total);
return 1;
}

static void castStack(struct pfCompile *pfc, FILE *f, struct pfParse *pp, 
	int stack);
/* Cast stack location. */


static void castCallToTuple(struct pfCompile *pfc, FILE *f, struct pfParse *pp, 
	int stack)
/* Cast function call results, which are on stack, to types specified by
 * cast list. */
{
struct pfParse *call = pp->children;
struct pfParse *castList = call->next;
struct pfParse *cast;
for (cast = castList; cast != NULL; cast = cast->next)
    {
    if (cast->type != pptPlaceholder)
	{
	castStack(pfc, f, cast, stack);
	}
    stack += 1;
    }
}

static void printLocalInterfaceMethodAssignments(struct pfCompile *pfc, 
	FILE *f, struct pfParse *pp, struct pfBaseType *classBase, 
	struct pfToken *tok, int stack)
/* Print assignments of methods declared in this interface. */
{
switch (pp->type)
    {
    case pptFlowDec:
    case pptToDec:
	fprintf(f, "_pf_face->%s = ", pp->name);
	codeMethodName(pfc, tok, f, classBase, pp->name, stack);
	fprintf(f, ";\n");
        break;
    }
for (pp = pp->children; pp != NULL; pp = pp->next)
    printLocalInterfaceMethodAssignments(pfc, f, pp, classBase, tok, stack);
}

static void printInterfaceMethodAssignments(struct pfCompile *pfc, FILE *f,
	struct pfBaseType *faceBase, struct pfBaseType *classBase, 
	struct pfToken *tok, int stack)
/* Print assignments of methods to interface, starting with
 * parent interface. */
{
if (faceBase->parent != NULL && faceBase->parent->def != NULL)
    {
    printInterfaceMethodAssignments(pfc, f, faceBase->parent, classBase, 
    	tok, stack);
    }
printLocalInterfaceMethodAssignments(pfc, f, faceBase->def, classBase, 
	tok, stack);
}

static void castClassToInterface(struct pfCompile *pfc, FILE *f, 
	struct pfParse *pp, int stack)
/* Generate code to allocate an interface type, fill in it's methods
 * and fill in it's object pointer with what's on the stack. */
{
struct pfBaseType *faceBase = pp->ty->base;
char *faceName = faceBase->cName;
struct pfParse *classPp = pp->children;
struct pfBaseType *classBase = classPp->ty->base;
char *className = classBase->cName;
fprintf(f, "{\n");
fprintf(f, "struct %s *_pf_face = _pf_need_mem(sizeof(struct %s));\n", 
	faceName, faceName);
fprintf(f, "struct _pf_object *_pf_obj = %s[%d].Obj;\n", cStackName, stack);
fprintf(f, "if (_pf_obj == 0)\n");
codeUseOfNil(f, pp);
fprintf(f, "_pf_face->_pf_refCount = 1;\n");
fprintf(f, "_pf_face->_pf_cleanup = _pf_cleanup_interface;\n");
fprintf(f, "_pf_face->_pf_obj = _pf_obj;\n");
fprintf(f, "_pf_face->_pf_objTypeId = ");
codeForType(pfc, f, classPp->ty);
fprintf(f, ";\n");
printInterfaceMethodAssignments(pfc, f, faceBase, classBase, pp->tok, stack);
fprintf(f, "%s[%d].v = _pf_face;\n", cStackName, stack);
fprintf(f, "}\n");
}

static void castStack(struct pfCompile *pfc, FILE *f, struct pfParse *pp, 
	int stack)
/* Cast stack location. */
{
switch(pp->type)
    {
    case pptCastBitToBit:
    case pptCastBitToByte:
    case pptCastBitToChar:
    case pptCastBitToShort:
    case pptCastBitToInt:
    case pptCastBitToLong:
    case pptCastBitToFloat:
    case pptCastBitToDouble:
    case pptCastByteToByte:
    case pptCastByteToChar:
    case pptCastByteToShort:
    case pptCastByteToInt:
    case pptCastByteToLong:
    case pptCastByteToFloat:
    case pptCastByteToDouble:
    case pptCastCharToByte:
    case pptCastCharToChar:
    case pptCastCharToShort:
    case pptCastCharToInt:
    case pptCastCharToLong:
    case pptCastCharToFloat:
    case pptCastCharToDouble:
    case pptCastShortToByte:
    case pptCastShortToChar:
    case pptCastShortToShort:
    case pptCastShortToInt:
    case pptCastShortToLong:
    case pptCastShortToFloat:
    case pptCastShortToDouble:
    case pptCastIntToByte:
    case pptCastIntToChar:
    case pptCastIntToShort:
    case pptCastIntToInt:
    case pptCastIntToLong:
    case pptCastIntToFloat:
    case pptCastIntToDouble:
    case pptCastLongToByte:
    case pptCastLongToChar:
    case pptCastLongToShort:
    case pptCastLongToInt:
    case pptCastLongToLong:
    case pptCastLongToFloat:
    case pptCastLongToDouble:
    case pptCastFloatToByte:
    case pptCastFloatToChar:
    case pptCastFloatToShort:
    case pptCastFloatToInt:
    case pptCastFloatToLong:
    case pptCastFloatToFloat:
    case pptCastFloatToDouble:
    case pptCastDoubleToByte:
    case pptCastDoubleToChar:
    case pptCastDoubleToShort:
    case pptCastDoubleToInt:
    case pptCastDoubleToLong:
    case pptCastDoubleToFloat:
    case pptCastDoubleToDouble:
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = ");
        codeParamAccess(pfc, f, pp->children->ty->base, stack);
	fprintf(f, ";\n");
	break;
    case pptCastByteToBit:
    case pptCastCharToBit:
    case pptCastShortToBit:
    case pptCastIntToBit:
    case pptCastLongToBit:
    case pptCastFloatToBit:
    case pptCastDoubleToBit:
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = ");
        codeParamAccess(pfc, f, pp->children->ty->base, stack);
	fprintf(f, " != 0");
	fprintf(f, ";\n");
	break;
    case pptCastObjectToBit:
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = (0 != ");
        codeParamAccess(pfc, f, pp->children->ty->base, stack);
	fprintf(f, ");\n");
	break;
    case pptCastStringToBit:
        {
	fprintf(f, "{_pf_String _pf_tmp = %s[%d].String; ", cStackName, stack);
	fprintf(f, "%s[%d].Bit = (_pf_tmp != 0 && _pf_tmp->size != 0);", cStackName, stack);
	fprintf(f, "}\n");
	break;
	}
    case pptCastBitToString:
    case pptCastByteToString:
    case pptCastShortToString:
    case pptCastIntToString:
    case pptCastLongToString:
    case pptCastFloatToString:
    case pptCastDoubleToString:
	{
	char *dest;
	if (pp->type == pptCastFloatToString || pp->type == pptCastDoubleToString)
	    dest = "double";
	else
	    dest = "long";
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = _pf_string_from_%s(", dest);
        codeParamAccess(pfc, f, pp->children->ty->base, stack);
	fprintf(f, ");\n");
	break;
	}
    case pptCastCharToString:
        {
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = _pf_string_new((char*)&");
        codeParamAccess(pfc, f, pp->children->ty->base, stack);
	fprintf(f, ",1);\n");
	break;
	}
    case pptCastTypedToVar:
	{
        codeParamAccess(pfc, f, pfc->varType, stack);
	fprintf(f, ".val.%s = ", vTypeKey(pfc, pp->children->ty->base));
	codeParamAccess(pfc, f, pp->children->ty->base, stack);
	fprintf(f, ";\n");
        codeParamAccess(pfc, f, pfc->varType, stack);
	fprintf(f, ".typeId = ");
	codeForType(pfc, f, pp->children->ty);
	fprintf(f, ";\n");
	break;
	}
    case pptCastVarToTyped:
        {
	fprintf(f, "if (");
	codeForType(pfc, f, pp->ty);
	fprintf(f, " != ");
        codeParamAccess(pfc, f, pfc->varType, stack);
	fprintf(f, ".typeId)\n");
	fprintf(f, "if (!_pf_check_types(");
	codeForType(pfc, f, pp->ty);
	fprintf(f, ", ");
        codeParamAccess(pfc, f, pfc->varType, stack);
	fprintf(f, ".typeId))\n");
	codeRunTimeError(f, pp, "run-time type mismatch");
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = ");
        codeParamAccess(pfc, f, pfc->varType, stack);
	fprintf(f, ".val.%s;\n", vTypeKey(pfc, pp->ty->base));
	break;
	}
    case pptCastCallToTuple:
        castCallToTuple(pfc, f, pp, stack);
	break;
    case pptCastClassToInterface:
        castClassToInterface(pfc, f, pp, stack);
	break;
    default:
	{
	internalErr();
	break;
	}
    }
}

static int codeStringAppend(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack)
/* Emit code to append to a string. */
{
struct pfParse *lval = pp->children;
struct pfParse *rval = lval->next;

codeExpression(pfc, f, lval, stack, FALSE);
fprintf(f, "if (%s[%d].String == 0)\n", cStackName, stack);
codeRunTimeError(f, lval, "string is nil");
codeExpression(pfc, f, rval, stack+1, TRUE);
fprintf(f, "_pf_cm_string_append(%s+%d);\n", cStackName, stack);
return 0;
}

static int codeTupleExpression(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, boolean addRef)
/* Code tuple as expression.  This just shoves each item
 * on tuple on stack one at at time. */
{
int total = 0;
struct pfParse *p;
for (p = pp->children; p != NULL; p = p->next)
    total += codeExpression(pfc, f, p, stack+total, addRef);
return total;
}

int codeExpression(struct pfCompile *pfc, FILE *f,
	struct pfParse *pp, int stack, boolean addRef)
/* Emit code for one expression.  Returns how many items added
 * to stack. */
{
switch (pp->type)
    {
    case pptTuple:
    case pptUniformTuple:
    case pptKeyVal:
        return codeTupleExpression(pfc, f, pp, stack, addRef);
    case pptClassAllocFromTuple:
        {
	int count = codeTupleExpression(pfc, f, pp->children, stack, addRef);
	codeTupleIntoClass(pfc, f, pp, pp->children, stack, count);
	return 1;
	}
    case pptClassAllocFromInit:
	return codeAllocInit(pfc, f, pp, stack);
    case pptNew:
        return codeNewOp(pfc, f, pp, stack);
    case pptParaMin:
    case pptParaMax:
    case pptParaArgMin:
    case pptParaArgMax:
    case pptParaAdd:
    case pptParaMultiply:
    case pptParaAnd:
    case pptParaOr:
        return codeParaExpSingle(pfc, f, pp, stack);
    case pptParaGet:
        return codeParaGet(pfc, f, pp, stack);
    case pptParaFilter:
        return codeParaFilter(pfc, f, pp, stack);
    case pptCall:
	return codeCall(pfc, f, pp, stack);
    case pptIndirectCall:
        return codeIndirectCall(pfc, f, pp, stack);
    case pptAssign:
	return codeAssignment(pfc, f, pp, stack, "=");
    case pptPlusEquals:
	if (pp->ty->base == pfc->dyStringType)
	    return codeStringAppend(pfc, f, pp, stack);
	else if (pp->ty->base == pfc->stringType)
	    internalErr();  /* Type checker should prevent this. */
	else
	    return codeAssignment(pfc, f, pp, stack, "+=");
	break;
    case pptMinusEquals:
	return codeAssignment(pfc, f, pp, stack, "-=");
    case pptMulEquals:
	return codeAssignment(pfc, f, pp, stack, "*=");
    case pptDivEquals:
	return codeAssignment(pfc, f, pp, stack, "/=");
    case pptVarInit:
    	codeVarInit(pfc, f, pp, stack);
	return 0;
    case pptVarUse:
	return codeVarUse(pfc, f, pp, stack, addRef);
    case pptIndex:
         return codeIndexRval(pfc, f, pp, stack, addRef);
    case pptDot:
         return codeDotRval(pfc, f, pp, stack);
    case pptPlus:
        return codeBinaryOp(pfc, f, pp, stack, "+");
    case pptMinus:
        return codeBinaryOp(pfc, f, pp, stack, "-");
    case pptMul:
        return codeBinaryOp(pfc, f, pp, stack, "*");
    case pptDiv:
        return codeBinaryOp(pfc, f, pp, stack, "/");
    case pptMod:
        return codeBinaryOp(pfc, f, pp, stack, "%");
    case pptGreater:
        return codeBinaryOp(pfc, f, pp, stack, ">");
    case pptGreaterOrEquals:
        return codeBinaryOp(pfc, f, pp, stack, ">=");
    case pptSame:
        return codeBinaryOp(pfc, f, pp, stack, "==");
    case pptNotSame:
        return codeBinaryOp(pfc, f, pp, stack, "!=");
    case pptLess:
        return codeBinaryOp(pfc, f, pp, stack, "<");
    case pptLessOrEquals:
        return codeBinaryOp(pfc, f, pp, stack, "<=");
    case pptLogAnd:
        return codeBinaryOp(pfc, f, pp, stack, "&&");
    case pptLogOr:
        return codeBinaryOp(pfc, f, pp, stack, "||");
    case pptBitAnd:
        return codeBinaryOp(pfc, f, pp, stack, "&");
    case pptBitOr:
        return codeBinaryOp(pfc, f, pp, stack, "|");
    case pptBitXor:
        return codeBinaryOp(pfc, f, pp, stack, "^");
    case pptShiftLeft:
        return codeBinaryOp(pfc, f, pp, stack, "<<");
    case pptShiftRight:
        return codeBinaryOp(pfc, f, pp, stack, ">>");
    case pptNegate:
         return codeUnaryOp(pfc, f, pp, stack, "-");
    case pptFlipBits:
         return codeUnaryOp(pfc, f, pp, stack, "~");
    case pptNot:
         return codeUnaryOp(pfc, f, pp, stack, "!");
    case pptConstBit:
    case pptConstByte:
    case pptConstShort:
    case pptConstInt:
    case pptConstLong:
    case pptConstFloat:
    case pptConstDouble:
        {
	struct pfToken *tok = pp->tok;
	codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = ");
	switch (tok->type)
	    {
	    case pftString:
		assert(pp->type == pptConstBit);
	        fprintf(f, "1;\n");
		break;
	    case pftFloat:
	        fprintf(f, "%f;\n", pp->tok->val.x);
		break;
	    case pftLong:
		fprintf(f, "%lldLL;\n", pp->tok->val.l);
		break;
	    case pftInt:
		fprintf(f, "%d;\n", pp->tok->val.i);
		break;
	    }
	return 1;
	}
    case pptConstChar:
        {
	assert(pp->tok->type == pftString || pp->tok->type == pftSubstitute);
	codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = %d;\n", pp->tok->val.s[0]);
	return 1;
	}
    case pptConstString:
        {
	assert(pp->tok->type == pftString || pp->tok->type == pftSubstitute);
	codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = _pf_string_from_const(");
	printEscapedString(f, pp->tok->val.s);
	fprintf(f, ");\n");
	return 1;
	}
    case pptConstZero:
        {
	if (pp->ty->base == pfc->varType)
	    {
	    fprintf(f, "%s[%d].Var.typeId = 0;\n", cStackName, stack);
	    fprintf(f, "%s[%d].Var.val.Int = 0;\n", cStackName, stack);
	    }
	else
	    {
	    codeParamAccess(pfc, f, pp->ty->base, stack);
	    fprintf(f, " = 0;\n");
	    }
	return 1;
	}
    case pptSubstitute:
        {
	struct pfParse *source = pp->children;
	struct pfParse *varTuple = source->next;
	int offset;
	offset = codeExpression(pfc, f, source, stack, TRUE);
	codeExpression(pfc, f, varTuple, stack+offset, TRUE);
	fprintf(f, "_pf_string_substitute(%s+%d);\n", cStackName, stack);
	return 1;
	}
    case pptStringCat:
        {
	return codeStringCat(pfc, f, pp, stack, addRef);
	}
    case pptStringDupe:
        {
	codeExpression(pfc, f, pp->children, stack, TRUE);
	fprintf(f, "_pf_string_make_independent_copy(%s+%d);\n", 
		cStackName, stack);
	return 1;
	}
    case pptCastBitToBit:
    case pptCastBitToByte:
    case pptCastBitToChar:
    case pptCastBitToShort:
    case pptCastBitToInt:
    case pptCastBitToLong:
    case pptCastBitToFloat:
    case pptCastBitToDouble:
    case pptCastByteToBit:
    case pptCastByteToByte:
    case pptCastByteToChar:
    case pptCastByteToShort:
    case pptCastByteToInt:
    case pptCastByteToLong:
    case pptCastByteToFloat:
    case pptCastByteToDouble:
    case pptCastCharToBit:
    case pptCastCharToByte:
    case pptCastCharToChar:
    case pptCastCharToShort:
    case pptCastCharToInt:
    case pptCastCharToLong:
    case pptCastCharToFloat:
    case pptCastCharToDouble:
    case pptCastShortToBit:
    case pptCastShortToByte:
    case pptCastShortToChar:
    case pptCastShortToShort:
    case pptCastShortToInt:
    case pptCastShortToLong:
    case pptCastShortToFloat:
    case pptCastShortToDouble:
    case pptCastIntToBit:
    case pptCastIntToByte:
    case pptCastIntToChar:
    case pptCastIntToShort:
    case pptCastIntToInt:
    case pptCastIntToLong:
    case pptCastIntToFloat:
    case pptCastIntToDouble:
    case pptCastLongToBit:
    case pptCastLongToByte:
    case pptCastLongToChar:
    case pptCastLongToShort:
    case pptCastLongToInt:
    case pptCastLongToLong:
    case pptCastLongToFloat:
    case pptCastLongToDouble:
    case pptCastFloatToBit:
    case pptCastFloatToByte:
    case pptCastFloatToChar:
    case pptCastFloatToShort:
    case pptCastFloatToInt:
    case pptCastFloatToLong:
    case pptCastFloatToFloat:
    case pptCastFloatToDouble:
    case pptCastDoubleToBit:
    case pptCastDoubleToByte:
    case pptCastDoubleToChar:
    case pptCastDoubleToShort:
    case pptCastDoubleToInt:
    case pptCastDoubleToLong:
    case pptCastDoubleToFloat:
    case pptCastDoubleToDouble:
    case pptCastObjectToBit:
    case pptCastStringToBit:
    case pptCastBitToString:
    case pptCastByteToString:
    case pptCastCharToString:
    case pptCastShortToString:
    case pptCastIntToString:
    case pptCastLongToString:
    case pptCastFloatToString:
    case pptCastDoubleToString:
    case pptCastTypedToVar:
    case pptCastVarToTyped:
    case pptCastCallToTuple:
    case pptCastClassToInterface:
	{
	codeExpression(pfc, f, pp->children, stack, addRef);
	castStack(pfc, f, pp, stack);
	return 1;
	}
    case pptCastFunctionToPointer:
        {
        codeParamAccess(pfc, f, pp->ty->base, stack);
	fprintf(f, " = %s%s;\n", pfcGlobalPrefix, pp->children->name);
	return 1;
	}
    default:
	{
	fprintf(f, "(%s expression)\n", pfParseTypeAsString(pp->type));
	return 0;
	}
    }
assert(FALSE);
return  0;
}

static void codeForeach(struct pfCompile *pfc, FILE *f,
	struct pfParse *foreach)
/* Emit C code for foreach statement. */
{
struct pfParse *collectionPp = foreach->children;
struct pfParse *elPp = collectionPp->next;
struct pfParse *body = elPp->next;
struct pfParse *elVarPp = NULL;

codeStartElInCollectionIteration(pfc, f, 0, 
	foreach->scope, elPp, collectionPp, FALSE);
codeStatement(pfc, f, body);
codeEndElInCollectionIteration(pfc, f, foreach->scope, elPp, 
	collectionPp, FALSE);
}

static void codeFor(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Emit C code for for statement. */
{
struct pfParse *init = pp->children;
struct pfParse *end = init->next;
struct pfParse *next = end->next;
struct pfParse *body = next->next;

fprintf(f, "{\n");
codeScopeVars(pfc, f, pp->scope, TRUE);
codeStatement(pfc, f, init);
fprintf(f, "for(;;)\n");
fprintf(f, "{\n");
if (next->type != pptNop)
    {
    codeExpression(pfc, f, end, 0, TRUE);
    fprintf(f, "if (!");
    codeParamAccess(pfc, f, pfc->bitType, 0);
    fprintf(f, ") break;\n");
    }
codeStatement(pfc, f, body);
codeStatement(pfc, f, next);
fprintf(f, "}\n");
fprintf(f, "}\n");
}

static void codeForEachCall(struct pfCompile *pfc, FILE *f, struct pfParse *foreach)
/* Emit C code for foreach call statement. */
{
struct pfParse *callPp = foreach->children;
struct pfParse *elPp = callPp->next;
struct pfParse *body = elPp->next;
struct pfParse *cast = body->next;
struct pfBaseType *base = callPp->ty->base;
int expSize;

/* Print element variable in a new scope. */
fprintf(f, "{\n");
codeScopeVars(pfc, f, foreach->scope, TRUE);
fprintf(f, "for(;;)\n");
fprintf(f, "{\n");
expSize = codeInitOrAssign(pfc, f, elPp, callPp, 0);
lvalOffStack(pfc, f, elPp, 0, "=", expSize, TRUE);
if (cast != NULL)
    castStack(pfc, f, cast, 0);
fprintf(f, "if (%s[0].Bit == 0)", cStackName);
fprintf(f, "   break;\n");
codeStatement(pfc, f, body);
fprintf(f, "}\n");
cleanupScopeVars(pfc, f, foreach->scope);
fprintf(f, "}\n");
}


static void codeWhile(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Emit C code for while statement. */
{
struct pfParse *end = pp->children;
struct pfParse *body = end->next;
fprintf(f, "for(;;)\n");
fprintf(f, "{\n");
codeExpression(pfc, f, end, 0, TRUE);
fprintf(f, "if (!");
codeParamAccess(pfc, f, pfc->bitType, 0);
fprintf(f, ") break;\n");
codeStatement(pfc, f, body);
fprintf(f, "}\n");
}

static void codeIf(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Emit C code for if statement. */
{
struct pfParse *cond = pp->children;
struct pfParse *trueBody = cond->next;
struct pfParse *falseBody = trueBody->next;
codeExpression(pfc, f, cond, 0, TRUE);
fprintf(f, "if (");
codeParamAccess(pfc, f, pfc->bitType, 0);
fprintf(f, ")\n");
fprintf(f, "{\n");
codeStatement(pfc, f, trueBody);
fprintf(f, "}\n");
if (falseBody != NULL)
    {
    fprintf(f, "else\n");
    fprintf(f, "{\n");
    codeStatement(pfc, f, falseBody);
    fprintf(f, "}\n");
    }
}

static void codeTry(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Emit C code for try statement. */
{
struct pfParse *tryBody = pp->children;
struct pfParse *catchVars = tryBody->next;
struct pfParse *catchBody = catchVars->next;
struct pfParse *exceptionVar = catchVars->children;
struct dyString *exceptionVarName = codeVarName(pfc, exceptionVar->var);
struct pfType *exceptionType = exceptionVar->ty;

fprintf(f, "{\n");
if (pfc->isFunc)
    fprintf(f, "_pf_Err_catch _pf_err = _pf_err_catch_new(&_pf_act, ");
else
    fprintf(f, "_pf_Err_catch _pf_err = _pf_err_catch_new(0, ");
codeForType(pfc, f, exceptionType);
fprintf(f, ");\n");

fprintf(f, "if (_pf_err_catch_start(_pf_err))\n");
fprintf(f, "{\n");
codeStatement(pfc, f, tryBody);
fprintf(f, "}\n");
fprintf(f, "_pf_err_catch_end(_pf_err);\n");
fprintf(f, "if (_pf_err_catch_got_err(_pf_err))\n");
fprintf(f, "{\n");
fprintf(f, "  /* catch block should start here. */\n");
if (!pfc->isFunc)
    {
    codeBaseType(pfc, f, exceptionType->base);
    fprintf(f, " %s = 0;\n", exceptionVarName->string);
    }
fprintf(f, "{\n");
fprintf(f, "%s = (", exceptionVarName->string);
codeBaseType(pfc, f, exceptionType->base);
fprintf(f, ")(_pf_err->err);\n");
codeStatement(pfc, f, catchBody);
codeCleanupVarNamed(pfc, f, exceptionType, exceptionVarName->string);
fprintf(f, "}\n");
fprintf(f, "  /* catch block should end here. */\n");
fprintf(f, "}\n");
fprintf(f, "_pf_err_catch_free(&_pf_err);\n");
fprintf(f, "}\n");
dyStringFree(&exceptionVarName);
}

static void codeArrayAppend(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Emit C code for array append . */
{
struct pfParse *array = pp->children;
struct pfParse *element = array->next;
int stack;
stack = codeExpression(pfc, f, array, 0, FALSE);
codeExpression(pfc, f, element, stack, TRUE);
fprintf(f, "_pf_array_append(%s[0].Array, &", cStackName);
codeParamAccess(pfc, f, element->ty->base, stack);
fprintf(f, ");\n");
}

void codeStatement(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Emit C code for one statement. */
{
switch (pp->type)
    {
    case pptCompound:
        {
	fprintf(f, "{\n");
	codeScope(pfc, f, pp, FALSE, NULL);
	fprintf(f, "}\n");
	break;
	}
    case pptCall:
    case pptIndirectCall:
    case pptAssign:
    case pptPlusEquals:
    case pptMinusEquals:
    case pptMulEquals:
    case pptDivEquals:
        codeExpression(pfc, f, pp, 0, TRUE);
	break;
    case pptTuple:
        {
	struct pfParse *p;
	for (p = pp->children; p != NULL; p = p->next)
	    codeStatement(pfc, f, p);
	break;
	}
    case pptVarInit:
	codeVarInit(pfc, f, pp, 0);
        break;
    case pptParaDo:
        codeParaDo(pfc, f, pp);
	break;
    case pptForeach:
	codeForeach(pfc, f, pp);
	break;
    case pptForEachCall:
        codeForEachCall(pfc, f, pp);
	break;
    case pptFor:
	codeFor(pfc, f, pp);
	break;
    case pptWhile:
        codeWhile(pfc, f, pp);
	break;
    case pptCase:
        codeCase(pfc, f, pp);
	break;
    case pptIf:
        codeIf(pfc, f, pp);
	break;
    case pptTry:
        codeTry(pfc, f, pp);
	break;
    case pptArrayAppend:
	codeArrayAppend(pfc, f, pp);
	break;
    case pptNop:
        break;
    case pptBreak:
        fprintf(f, "break;\n");
        break;
    case pptContinue:
        fprintf(f, "continue;\n");
        break;
    case pptReturn:
        fprintf(f, "goto _pf_cleanup;\n");
        break;
    case pptInclude:
    case pptImport:
        fprintf(f, "_pf_entry_%s(%s);\n", mangledModuleName(pp->name), 
		cStackName);
	break;
    default:
        fprintf(f, "[%s statement];\n", pfParseTypeAsString(pp->type));
	break;
    }
}

static void printPrototype(FILE *f, struct pfParse *funcDec, struct pfParse *class,
	boolean activeModule, boolean printSemi)
/* Print prototype for function call. */
{
if (class)
    {
    fprintf(f, "void %s_%s(", class->ty->base->methodPrefix, funcDec->name);
    fprintf(f, "%s *%s)",  cStackType, cStackName);
    }
else
    {
    enum pfAccessType access = funcDec->ty->access;
    if (access != paGlobal)
	{
	if (activeModule)
	    fprintf(f, "static ");
	else
	    return;
	}
    fprintf(f, "void %s%s(%s *%s)", pfcGlobalPrefix, funcDec->name, 
    	cStackType, cStackName);
    }
if (printSemi)
    fprintf(f, ";\n");
}

static void rPrintPrototypes(FILE *f, struct pfParse *pp, struct pfParse *class,
	boolean activeModule)
/* Recursively print out function prototypes in C. */
{
switch (pp->type)
    {
    case pptClass:
        class = pp;
	break;
    case pptToDec:
    case pptFlowDec:
	printPrototype(f, pp, class, activeModule, TRUE);
        break;
    }
for (pp=pp->children; pp != NULL; pp = pp->next)
    rPrintPrototypes(f, pp, class, activeModule);
}

static void declareStaticVars(struct pfCompile *pfc, FILE *f, 
	struct pfParse *funcDec, struct pfParse *pp,
	struct pfParse *class)
/* Declare static variables inside of function */
{
if (pp->type == pptVarInit)
    {
    struct pfType *type = pp->ty;
    if (type->access == paStatic)
        {
	fprintf(f, "static ");
	codeBaseType(pfc, f, type->base);
	fprintf(f, " ");
	printVarName(pfc, f, pp->var);
	fprintf(f, ";\n");
	}
    }
for (pp = pp->children; pp != NULL; pp = pp->next)
    declareStaticVars(pfc, f, funcDec, pp, class);
}

static void codeFunction(struct pfCompile *pfc, FILE *f, 
	struct pfParse *funcDec, struct pfParse *class)
/* Emit C code for function.  If class is non-null
 * then decorate it with 'self' so as to be a method. */
{
struct pfVar *funcVar = funcDec->var;
struct ctar *ctar = funcDec->var->ctar;
struct pfType *funcType = funcVar->ty;
struct pfType *inTuple = funcType->children;
struct pfType *outTuple = inTuple->next;
struct pfParse *body = funcDec->children->next->next->next;
bool oldIsFunc = pfc->isFunc;

if (body != NULL)
    {
    pfc->isFunc = TRUE;
    declareStaticVars(pfc, f, funcDec, body, class);
    printPrototype(f, funcDec, class, TRUE, FALSE);
    fprintf(f, "\n{\n");

    /* Print out activation record. */
	{
	ctarCodeLocalStruct(ctar, pfc, f, NULL);
	ctarCodePush(ctar, pfc, f);
	}

    /* Print out input parameters. */
	{
	struct pfType *in;
	int inIx = 0;
	if (class)
	    {
	    fprintf(f, "%sself = ", localPrefix);
	    codeParamAccess(pfc, f, class->ty->base, 0);
	    fprintf(f, ";\n");
	    inIx += 1;
	    if (pfBaseIsDerivedClass(class->ty->base))
		{
		fprintf(f, "%sparent = ", localPrefix);
		codeParamAccess(pfc, f, class->ty->base, 0);
		fprintf(f, ";\n");
		/* No +1 here, we just reuse self as parent. */
		}
	    }
	for (in = inTuple->children; in != NULL; in = in->next)
	    {
	    fprintf(f, "%s%s = ", localPrefix, in->fieldName);
	    codeParamAccess(pfc, f, in->base, inIx);
	    fprintf(f, ";\n");
	    inIx += 1;
	    }
	}

    /* Print out output parameters. */
	{
	/* Nothing to do here, since did bulk local zero init. */
	}

    /* Print out body (which is a compound statement) */
    codeStatement(pfc, f, body);

    /* Print exit label for returns. */
    fprintf(f, "_pf_cleanup: ;\n");

    /* Decrement ref counts on input variables. */
	{
	struct pfType *in;
	struct dyString *name = dyStringNew(0);
	for (in = inTuple->children; in != NULL; in = in->next)
	    {
	    dyStringClear(name);
	    dyStringPrintf(name, "%s%s", localPrefix, in->fieldName);
	    codeCleanupVarNamed(pfc, f, in, name->string);
	    }
	dyStringFree(&name);
	}

    /* Save the output. */
	{
	int outIx = 0;
	struct pfType *out;
	for (out = outTuple->children; out != NULL; out = out->next)
	    {
	    codeParamAccess(pfc, f, out->base, outIx);
	    fprintf(f, " = %s%s;\n", localPrefix, out->fieldName);
	    outIx += 1;
	    }
	}

    /* Close out function. */
    ctarCodePop(ctar, pfc, f);
    fprintf(f, "}\n\n");
    pfc->isFunc = oldIsFunc;
    }
}

static void printPolyFunTable(struct pfCompile *pfc, FILE *f, 
	struct pfBaseType *base)
/* Print polymorphic function table. */
{
if (base->polyList != NULL)
    {
    struct pfPolyFunRef *pfr;
    fprintf(f, "static _pf_polyFunType _pf_pf%d_%s[] = {\n", base->scope->id, base->name);
    for (pfr = base->polyList; pfr != NULL; pfr = pfr->next)
        {
	struct pfBaseType *b = pfr->class;
	fprintf(f, "  %s_%s,\n", b->methodPrefix,
		pfr->method->fieldName);
	}
    fprintf(f, "};\n");
    }
}

static void codeStaticCleanups(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Print out any static assignments in parse tree. */
{
if (pp->type == pptVarInit && pp->ty->access == paStatic)
    codeCleanupVar(pfc, f, pp->var);
for (pp = pp->children; pp != NULL; pp = pp->next)
    codeStaticCleanups(pfc, f, pp);
}

static void codeStaticInits(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Print out any static assignments in parse tree. */
{
if (pp->type == pptVarInit && pp->ty->access == paStatic)
    codeStatement(pfc, f, pp);
for (pp = pp->children; pp != NULL; pp = pp->next)
    codeStaticInits(pfc, f, pp);
}


static void rPrintClasses(struct pfCompile *pfc, FILE *f, struct pfParse *pp,
	boolean printPolyFun)
/* Print out class definitions. */
{
if (pp->type == pptClass)
    {
    struct pfBaseType *base = pp->ty->base;
    fprintf(f, "struct %s {\n", base->cName);
    fprintf(f, "int _pf_refCount;\n");
    fprintf(f, "void (*_pf_cleanup)(struct %s *obj, int typeId);\n", 
    	base->cName);
    fprintf(f, "_pf_polyFunType *_pf_polyFun;\n");
    rPrintFields(pfc, f, base); 
    fprintf(f, "};\n");
    if (printPolyFun)
	printPolyFunTable(pfc, f, base);
    fprintf(f, "\n");
    }
for (pp = pp->children; pp != NULL; pp = pp->next)
    rPrintClasses(pfc, f, pp, printPolyFun);
}

static void rPrintFuncPointersInInterface(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Print out function declarations in parse tree as function pointers. */
{
switch (pp->type)
    {
    case pptToDec:
    case pptFlowDec:
	fprintf(f, "void (*%s)(%s *%s);\n", pp->name, cStackType, cStackName);
        break;
    }
for (pp = pp->children; pp != NULL; pp = pp->next)
    rPrintFuncPointersInInterface(pfc, f, pp);
}

static void rPrintInterfaceElements(struct pfCompile *pfc, FILE *f, struct pfBaseType *base)
/* Print out function pointer declarations for all elements in interface and it's parents. */
{
/* Print out elements from parent interfaces if any first. */
if (base->parent != NULL && base->parent->def != NULL)
    rPrintInterfaceElements(pfc, f, base->parent);
rPrintFuncPointersInInterface(pfc, f, base->def);
}

static void rPrintInterfaces(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Print out interface definition. */
{
if (pp->type == pptInterface)
     {
     struct pfBaseType *base = pp->ty->base;
     struct pfParse *ppType = pp->children;
     struct pfParse *ppCompound = ppType->next;
     fprintf(f, "struct %s {\n", base->cName);
     fprintf(f, "int _pf_refCount;\n");
     fprintf(f, "void (*_pf_cleanup)(void *obj, int typeId);\n");
     fprintf(f, "void *_pf_obj;\n");
     fprintf(f, "int _pf_objTypeId;\n");
     rPrintInterfaceElements(pfc, f, base);
     fprintf(f, "};\n\n");
     }
for (pp = pp->children; pp != NULL; pp = pp->next)
    rPrintInterfaces(pfc, f, pp);
}


static void rPrintFuncDeclarations(struct pfCompile *pfc, FILE *f, 
	struct pfParse *pp, struct pfParse *class)
/* Print out function declarations. */
{
switch (pp->type)
    {
    case pptToDec:
    case pptFlowDec:
	codeFunction(pfc, f, pp, class);
	break;
    case pptClass:
        class = pp;
	break;
    }
for (pp = pp->children; pp != NULL; pp = pp->next)
    rPrintFuncDeclarations(pfc, f, pp, class);
}

static void codeAllButStaticInits(struct pfCompile *pfc, FILE *f, struct pfParse *pp)
/* Code everything *but* the static initializations. */
{
struct pfParse *p;
for (p = pp->children; p != NULL; p = p->next)
    {
    switch (p->type)
        {
	case pptToDec:
	case pptFlowDec:
	case pptNop:
	case pptClass:
	case pptInterface:
	    break;
	case pptTuple:
	    codeAllButStaticInits(pfc, f, p);
	    break;
	case pptVarInit:
	    if (p->access != paStatic)
		codeStatement(pfc, f, p);
	    break;
	default:
	    codeStatement(pfc, f, p);
	    break;
	}
    }
}

static void codeScope(struct pfCompile *pfc, FILE *f, struct pfParse *pp, 
	boolean isModuleScope, struct ctar *ctarList)
/* Print types and then variables from scope. */
{
struct pfScope *scope = pp->scope;
struct hashEl *hel, *helList;
struct pfParse *p;
boolean gotFunc = FALSE, gotVar = FALSE;


/* Get declaration list and sort it. */
helList = hashElListHash(scope->vars);
slSort(&helList, hashElCmp);

/* Print out variables. */
if (isModuleScope)
    {
    for (hel = helList; hel != NULL; hel = hel->next)
        {
	struct pfVar *var = hel->val;
	var->isExternal = !pfParseIsInside(pp, var->parse);
	}
    }
codeVarsInHelList(pfc, f, helList, !isModuleScope, isModuleScope);

/* Print out function declarations */
rPrintFuncDeclarations(pfc, f, pp, NULL);

/* Print out other statements */
if (isModuleScope)
    {
    fprintf(f, "void _pf_entry_%s(%s *%s)\n{\n", mangledModuleName(pp->name), 
    	cStackType, cStackName);
    fprintf(f, "static int firstTime = 1;\n");
    fprintf(f, "if (firstTime)\n");
    fprintf(f, "{\n");
    fprintf(f, "firstTime = 0;\n");
    fprintf(f, "%s.next = %s;\n", cModuleRuntimeName, cModuleRuntimeList);
    fprintf(f, "%s = &%s;\n", cModuleRuntimeList, cModuleRuntimeName);
    ctarCodeStartupCall(ctarList, pfc, f);
    codeStaticInits(pfc, f, pp);
    }
codeAllButStaticInits(pfc, f, pp);

if (isModuleScope)
    {
    fprintf(f, "}\n");
    fprintf(f, "}\n\n");

    cPrintModuleCleanupPrototype(f);
    fprintf(f,"\n{\n");
    codeCleanupVarsInHelList(pfc, f, helList);
    codeStaticCleanups(pfc, f, pp);
    fprintf(f, "}\n");
    }
else
    {
    /* Print out any needed cleanups. */
    codeCleanupVarsInHelList(pfc, f, helList);
    }

hashElFreeList(&helList);
}

static void printPolyFuncConnections(struct pfCompile *pfc,
	struct slRef *scopeRefs, struct pfParse *module, FILE *f)
/* Print out poly_info table that connects polymorphic function
 * tables to the classes they belong to. */
{
struct slRef *ref;
fprintf(f, "struct _pf_poly_info _pf_poly_info_%s[] = {\n", 
	mangledModuleName(module->name));
for (ref = scopeRefs; ref != NULL; ref = ref->next)
    {
    struct pfScope *scope = ref->val;
    struct pfBaseType *class = scope->class;
    if (class != NULL && class->polyList != NULL && 
    	pfParseIsInside(module, class->def))
        {
	fprintf(f, "  {\"%s\", _pf_pf%d_%s},\n", class->name, class->scope->id, class->name);
	}
    }
fprintf(f, "  {0, 0},\n");  /* Make sure have at least one. */
fprintf(f, "};\n");
}

static void rAddCompileTimeActivationRecords(struct pfParse *pp, 
	struct ctar **pCtar)
/* Print out function declarations. */
{
switch (pp->type)
    {
    case pptToDec:
    case pptFlowDec:
	{
	struct pfParse *body = pp->children->next->next->next;
	if (body)
	    {
	    struct ctar *ctar = ctarOnFunction(pp);
	    slAddHead(pCtar, ctar);
	    }
	break;
	}
    }
for (pp = pp->children; pp != NULL; pp = pp->next)
    rAddCompileTimeActivationRecords(pp, pCtar);
}

static void printGlobalVarsInScope(struct pfCompile *pfc, FILE *f, 
	struct pfScope *scope)
/* Print all the global variables in scope. */
{
struct hashEl *hel = hel, *varList = hashElListHash(scope->vars);

slSort(&varList, hashElCmp);
for (hel = varList; hel != NULL; hel = hel->next)
    {
    struct pfVar *var = hel->val;
    struct pfType *type = var->ty;
    if (type->tyty == tytyVariable)
        {
	enum pfAccessType access = var->ty->access;
	if (access == paGlobal || access == paWritable)
	    {
	    fprintf(f, "extern ");
	    codeBaseType(pfc, f, type->base);
	    fprintf(f, " ");
	    printVarName(pfc, f, var);
	    fprintf(f, ";\n");
	    }
	}
    }
slFreeList(&varList);
}

void pfCodeC(struct pfCompile *pfc, struct pfParse *program, char *baseDir, 
	char *mainName)
/* Generate C code for program. */
{
FILE *f;
struct pfParse *toCode, *module;
struct pfScope *scope;
struct pfParse *mainModule = NULL;

pfc->runTypeHash = hashNew(0);

/* Generate code for each module that is not already compiled. */
for (toCode = program->children; toCode != NULL; toCode = toCode->next)
    {
    struct ctar *ctarList = NULL;
    if (toCode->type == pptModule || toCode->type == pptMainModule)
	{
	struct pfModule *mod = hashMustFindVal(pfc->moduleHash, toCode->name);
	char *fileName = replaceSuffix(mod->fileName, ".pf", ".c");
	char *moduleName = mangledModuleName(toCode->name);
	if (toCode->type == pptMainModule)
	    mainModule = toCode;
	f = mustOpen(fileName, "w");

	pfc->moduleTypeHash = hashNew(0);
	cPrintPreamble(pfc, f, fileName, TRUE);
	fprintf(f, "extern struct %s %s_%s[];\n", recodedStructType, recodedTypeTableName,
		moduleName);
	fprintf(f, "static struct %s *%s = %s_%s;\n\n",
		recodedStructType, recodedTypeTableName, recodedTypeTableName, 
		moduleName);
	cPrintModuleCleanupPrototype(f);
	fprintf(f, ";\n");
	fprintf(f, "static struct %s %s = {0, \"%s\", %s};\n",
		cModuleRuntimeType, cModuleRuntimeName, moduleName,
		moduleCleanupName);
	fprintf(f, "\n");

	/* Print function prototypes and class definitions for all modules */
	for (module = program->children; module != NULL; module = module->next)
	    {
	    boolean activeModule = (toCode == module);
	    fprintf(f, "/* Prototypes in ParaFlow module %s */\n", module->name);
	    if (module->name[0] != '<')
		fprintf(f, "void _pf_entry_%s(%s *stack);\n", 
			mangledModuleName(module->name), cStackType);
	    rPrintPrototypes(f, module, NULL, activeModule);
	    fprintf(f, "\n");
	    fprintf(f, "/* Class definitions in module %s */\n", module->name);
	    rPrintClasses(pfc, f, module, activeModule);
	    fprintf(f, "/* Interface definitions in module %s */\n", module->name);
	    rPrintInterfaces(pfc, f, module);
	    if (module != toCode)
		{
		fprintf(f, "/* Global variables in module %s */\n", module->name);
		printGlobalVarsInScope(pfc, f, module->scope);
		}
	    fprintf(f, "\n");
	    }


	for (module = program->children; module != NULL; module = module->next)
	    {
	    if (module == toCode)
		{
		rAddCompileTimeActivationRecords(module, &ctarList);
		slReverse(&ctarList);
		verbose(3, "Coding %s\n", module->name);
		fprintf(f, "/* ParaFlow module %s */\n\n", module->name);
		fprintf(f, "\n");
		ctarCodeFixedParts(ctarList, pfc, f);
		fprintf(f, "\n");
		codeParaBlocks(pfc, f, module);
		fprintf(f, "\n");
		codeScope(pfc, f, module, TRUE, ctarList);
		fprintf(f, "\n");
		printPolyFuncConnections(pfc, pfc->scopeRefList, module, f);
		}
	    }
	recodedTypeTableToC(pfc, toCode->name, f);
	freeHashAndVals(&pfc->moduleTypeHash);
	carefulClose(&f);
	freeMem(fileName);
	}
    }
cMain(pfc, program, mainName);
}

