/* Stubby - Generate stubs for dynamic-link libraries.
 * Copyright 1999 Tom Rothamel
 *
 * Stubby 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 2, or (at your option)
 * any later version. It 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * This program generates another computer program. I do not assert a      
 * copyright on the generated program that is the normal output of this    
 * program. This is _not_, however, an authorization for you to modify     
 * this program to cause it to output more of itself than necessary for    
 * its proper operation in order to circumvent my copyright.               
 */

/* This file contains functions to manipulate parse table entries. PTEs
 * are used to convey information from the parser to the code generation
 * routines.
 */

#include "str.h"
#include "pte.h"
#include <malloc.h>

PTE *newPTE() {
	PTE *pte;

	pte = calloc(sizeof(PTE), 1);

	pte->next = NULL;
	pte->type = PTE_UNKNOWN;
	pte->proto = NULL;
	pte->name = NULL;
	pte->args = NULL;
	pte->fproto = NULL;
	pte->pdepth = 0;
	
	return pte;
}

void delPTE(PTE *pte) {
	if (pte->next) delPTE(pte->next);

	if (pte->proto) free(pte->proto);
	if (pte->name) free(pte->name);
	if (pte->fproto) delPTE(pte->fproto);
	if (pte->args) delPTE(pte->args);
				
        free(pte);
}

/* This creates a string with l asterisks. Used to stringify pointers. */
char *strptr(int l) {
	int i;
	char *s;

	s = strdup("");

	for (i = 0; i < l; i++) {
		s = strappend(s, "*");
	}

	return s;
}

/* This converts a list of variables or prototypes into a string. */
char *strargs(PTE *pte) {
	char *s;
	
	s = strdup("(");

	pte = pte->args;
	while (pte) {
		s = straf(s, strpte(pte));
		if (pte->next) s = strappend(s, ", ");
		pte = pte->next;
	}

       s = strappend(s, ")");
       return s;
}

/* This converts an arbitrary PTE into a string. */
char *strpte(PTE *pte) {
	char *s;

	if (!pte) return strdup("void ");
	
	switch (pte->type) {
	case PTE_PROTO:
		return strdup(pte->proto);
	case PTE_PROTOF:
		s = strpte(pte->fproto);
		s = strappend(s, "(");
		s = straf(s, strptr(pte->pdepth));
		s = strappend(s, ")");
		s = straf(s, strargs(pte));
		return s;
	case PTE_VAR:
		s = strdup(pte->proto);
		s = strappend(s, pte->name);
		return s;
	case PTE_VARF:
		s = strpte(pte->fproto);
		s = strappend(s, "(");
		s = straf(s, strptr(pte->pdepth));
		s = strappend(s, pte->name);
		s = strappend(s, ")");
		s = straf(s, strargs(pte));
		return s;
	case PTE_FUNCTION:
		if (!pte->fproto) {
			s = strdup("void ");
		} else {
			s = strpte(pte->fproto);
		}
		s = strappend(s, pte->name);
		s = straf(s, strargs(pte));
		return s;
	}
}		

/* This promotes a PTE, renaming it in the process. Promotion converts a
 * prototype into a full-fledged variable. */
void promotepte(PTE *pte, char *name) {
	switch(pte->type) {
	case PTE_PROTO:
		pte->type = PTE_VAR;
		break;
	case PTE_PROTOF:
		pte->type = PTE_VARF;
		break;
	case PTE_FUNCTION:
		error("Trying to promote a function named %s.\n", pte->name);
		exit(-1);
	}

	if (pte->name) free(pte->name);
	pte->name = strdup(name);
}
		       
