ftp.nice.ch/pub/next/developer/languages/ada/Adaed.1.11.s.tar.gz#/Adaed-1.11.0a/reduce.c

This is reduce.c in view mode; [Download] [Up]

/*
 * Copyright (C) 1985-1992  New York University
 * 
 * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
 * warranty (none) and distribution info and also the GNU General Public
 * License for more details.

 */
/* This file contains various functions needed for reduce actions */

#include "adared.h"
#include "prsutilprots.h"
#include "errsprots.h"
#include "adalexprots.h"
#include "pspansprots.h"
#include "reduceprots.h"

static void pragma_warning(struct ast *);
static void remove_link(struct ast *, struct two_pool **, struct two_pool *);
static int in_label_set(struct ast *, struct two_pool *);
static int is_pragma(int);

/* define PDEBUG to trace pragma procedures */


void free_everything(struct ast *node)				/*;free_everything*/
{
	/* Recursively free all nodes in the tree beginning at node, and
	 * free all list structures and AST structures where they exist.
	 */

	struct two_pool *listptr;
	int i;

#ifdef FDEBUG
	if (trcopt)
		fprintf(errfile,"Freeing node 0x%x, kind = %d\n",node,node->kind);
#endif
	/* check to see if the node has already been freed */
	if (node->kind == AS_FREE)
		return;
	if (islist_node[node->kind]) {
#ifdef FDEBUG
		if (trcopt)
			fprintf(errfile,"Traversing through list\n");
#endif
		if (node->links.list != NULL) {
			listptr = node->links.list;
			do {
				listptr = listptr->link;
				free_everything(listptr->val.node);
			}	    while (listptr != node->links.list);
			TFREE(node->links.list->link,node->links.list);
		}
	}
	else if (isast_node[node->kind]) {
#ifdef FDEBUG
		if (trcopt)
			fprintf(errfile,"Traversing through tree\n");
#endif
		for (i = 0; i < MAX_AST && (node->links.subast)[i] != NULL; i++)
			if ((node->links.subast)[i] != opt_node)
				free_everything((node->links.subast)[i]);
		astfree(node->links.subast);
	}
	nodefree(node);
#ifdef FDEBUG
	if (trcopt)
		fprintf(errfile,"Returning\n");
#endif
}

void set_span(struct ast *node, struct tok_loc *span)		/*;set_span*/
{
	/* Set the spans field of node to match the given spans. */
	node->span.line = span->line;
	node->span.col = span->col;
}

struct two_pool *initlist(struct ast *node)				/*;initlist*/
{
	/* Allocate a single list structure (struct two_pool), set its data to
	 * be a pointer to the node given, and set its link field to point
	 * to itself, since tree node lists are circular.
	 */
	struct two_pool *tmp;

	tmp = TALLOC();
	tmp->val.node = node;
	tmp->link = tmp;
	return(tmp);
}

struct ast **new_ast1(struct ast *a1)					/*;new_ast1*/
{
	/* Allocate an array to hold pointers to the children of a node
	 * in the AST, and set elements of the array to the values given. This
	 * function may be called with fewer than the 4 parameters below, in which
	 * case the parameters given will be used properly, and undefined (garbage)
	 * values will be put in the latter part of the array.
	 */

	struct ast **tmp;

	tmp = astalloc();
	tmp[0] = a1;
	tmp[1] = 0;
	tmp[2] = 0;
	tmp[3] = 0;
	return(tmp);
}

struct ast **new_ast2(struct ast *a1, struct ast *a2)			/*;new_ast2*/
{
	struct ast **tmp;

	tmp = astalloc();
	tmp[0] = a1;
	tmp[1] = a2;
	tmp[2] = 0;
	tmp[3] = 0;
	return(tmp);
}

struct ast **new_ast3(struct ast *a1, struct ast *a2, struct ast *a3)
																/*;new_ast3*/
{
	struct ast **tmp;

	tmp = astalloc();
	tmp[0] = a1;
	tmp[1] = a2;
	tmp[2] = a3;
	tmp[3] = 0;
	return(tmp);
}

struct ast **new_ast4(struct ast *a1, struct ast *a2, struct ast *a3,
  struct ast *a4)												/*;new_ast4*/
{
	struct ast **tmp;

	tmp = astalloc();
	tmp[0] = a1;
	tmp[1] = a2;
	tmp[2] = a3;
	tmp[3] = a4;
	return(tmp);
}

struct two_pool *concatl(struct two_pool *bottom,struct two_pool *nextlist)
															/*;concatl*/
{
	/* Concatenate circular linked lists of structs of type two_pool
	 * together, returning the new end pointer. There are two such
	 * functions: concatl catenates two lists, concatl3 catenates three.
	 */
	struct two_pool *tmp;

	if (bottom==(struct two_pool *)0) bottom = nextlist;
	if (nextlist!=(struct two_pool *)0) {
		tmp = bottom->link;
		bottom->link = nextlist->link;
		nextlist->link = tmp;
		bottom = nextlist;
	}
	return(bottom);
}

struct two_pool *concatl3(struct two_pool *bottom, struct two_pool *nextlist,
  struct two_pool *list3)									/*;concatl3*/
{
	return concatl(concatl(bottom,nextlist),list3);
}

void append(struct ast *orignode, struct ast *node)			/*;append*/
{
	/* Given two nodes from the AST, orignode with a list of children,
	 * and a new node node, allocate a new list structure for node and append
	 * it to the list of children, and set the spans of orignode so they remain
	 * correct.
	 */

	struct two_pool *tmp;

	tmp = TALLOC();
	tmp->val.node = node;
	if (orignode->links.list == (struct two_pool *)0)
		tmp->link = tmp;
	else {
		tmp->link = orignode->links.list->link;
		orignode->links.list->link = tmp;
	}
	orignode->links.list = tmp;
}

void prepend(struct ast *node, struct ast *orignode)		/*;prepend*/
{
	/* Given two nodes from the AST, orignode with a list of children,
	 * and a new node node, allocate a new list structure for node and
	 * prepend it to the list of children, and set the spans of orignode
	 * so they remain correct.
	 */

	struct two_pool *tmp;

	tmp = TALLOC();
	tmp->val.node = node;
	if (orignode->links.list == (struct two_pool *)0)
		orignode->links.list = tmp->link = tmp;
	else {
		tmp->link = orignode->links.list->link;
		orignode->links.list->link = tmp;
	}
}

struct ast *binary_operator(struct ast *optr, struct ast *expr1,
  struct ast *expr2)									/*;binary_operator*/
{
	/* Set up the AST node for a binary operator. */

	struct ast *node, *arg_list_node;
	struct two_pool *tmp;

	NN(AS_OP);
	arg_list_node = new_node(AS_LIST);
	(arg_list_node->links.list = TALLOC())->val.node = expr2;
	(arg_list_node->links.list->link = tmp = TALLOC())->val.node = expr1;
	tmp->link = arg_list_node->links.list;
	NAST2(optr,arg_list_node);
	return(node);
}

struct ast *unary_operator(struct ast *optr, struct ast *expr)
														/*;unary_operator*/
{
	/* Set up the AST node for a unary operator. */
	struct ast *node, *arg_list_node;

	node = new_node(AS_UN_OP);
	arg_list_node = new_node(AS_LIST);
	arg_list_node->links.list = initlist(expr);
	NAST2(optr,arg_list_node);
	return(node);
}

int check_expanded_name(struct ast *name)			/*;check_expanded_name*/
{
	/* Make sure an expanded name node is valid. */

#define sub_expanded_name ((name->links.subast)[0])
	return((name->kind == AS_SELECTOR) ? 
	  check_expanded_name(sub_expanded_name) : (name->kind == AS_SIMPLE_NAME));
#undef sub_expanded_name
}

void check_discrete_range(struct ast *discrete_range) /*;check_discrete_range*/
{
	/* Check whether a discrete range node is valid. */

	switch (discrete_range->kind)
	{
	case AS_RANGE_EXPRESSION :
#define name (discrete_range->links.subast)[0]
		if (!check_expanded_name(name))
			syntax_err(SPAN(discrete_range),
			  "Invalid discrete_range specification");
		else
			discrete_range->kind = AS_NAME;
		break;
#undef name
	case AS_RANGE_ATTRIBUTE :
	case AS_SUBTYPE :
		break;
	default :
		syntax_err(SPAN(discrete_range),
		  "Invalid discrete_range specification");
	}
}

static void pragma_warning(struct ast *pragma_node)			/*;pragma_warning*/
{
	/* Give a warning that a pragma is ignored. */

	char msg[MAXLINE + 30];

#define id (pragma_node->links.subast)[0]
	sprintf(msg,"Pragma %s is ignored", namelist(id->links.val));
	prs_warning(SPAN(pragma_node),msg);
#undef id
}

void pragmalist_warning(struct ast *list_node)		/*;pragmalist_warning*/
{
	/* For all nodes in the list of list_node give a warning the the pragma
	 * is invalid.
	 */

	LLOOPTOP(list_node->links.list,tmp)
	    pragma_warning(tmp->val.node);
	LLOOPBOTTOM(tmp)
}

static void remove_link(struct ast *pragma_node, struct two_pool **current,
  struct two_pool *prev)								/*;remove_link*/
{
	/* Remove a node (pragma_node) from a circular linked list of nodes. */

	if ((*current)->link != *current)
		prev->link = (*current)->link;
	else
		pragma_node->links.list = (struct two_pool *) 0;
	nodefree((*current)->val.node);
	TFREE(*current,*current);
	*current = prev;
}

void check_pragmas(struct ast *pragma_node, int (*allowed_test)(int))
													/*;check_pragmas*/
{
	/* Check that a pragma is valid. */

	struct two_pool *old_list, *prev, *current;
	int id;
	int last;

#ifdef PDEBUG
	printf("enter check_pragmas\n");
#endif
	if ((old_list = prev = current = pragma_node->links.list) != 
	  (struct two_pool *)0)
	{
		do {
			last = (current = current->link) == old_list;
			id = (current->val.node->links.subast)[0]->links.val;
#ifdef PDEBUG
			printf("check_pragma id %d\n",id);
#endif
			if (is_pragma(id) && (*allowed_test)(id - MIN_PRAGMA)) {
				if (strcmp(namelist(id),"PRIORITY")
				  && strcmp(namelist(id),"ELABORATE")
				  && strcmp(namelist(id),"INTERFACE"))
				{
					pragma_warning(current->val.node);
					remove_link(pragma_node,&current,prev);
				}
			}
			else if (is_pragma(id) && ispredef_pragma[id - MIN_PRAGMA])
			{
				char msg[200];

				sprintf(msg,"Pragma %s is not valid in this context",
				  namelist(id));
				prs_warning(SPAN(current->val.node),msg);
				remove_link(pragma_node,&current,prev);
			}
			else if (!(is_pragma(id) && isimpldef_pragma[id - MIN_PRAGMA])
			  && strcmp(namelist(id),"OPTIMIZE"))
			{
				pragma_warning(current->val.node);
				remove_link(pragma_node,&current,prev);
			}
			prev = current;
		}	while (!last);
	}
}

int isoverloadable_op(char *str)				/*;isoverloadable_op*/
{
	/* Check whether a string represnts an overloadable operator by
	 * comparing against all overloadable operators.
	 */

	char tmp[MAXLINE + 1];
	int i;

	strcpy(tmp,str);
	convtolower(tmp);
	for (i = 0; i < NUMOVERLOADOPS; i++)
		if (!strcmp(tmp,overloadable_operators[i]))
			return(1);
	return(0);
}

void make_id(int n)											/*;make_id*/
{
	/* Allocate a node for a simple name whose value and span are* known by
	 * looking at the nth symbol in the right hand side of the reduction,
	 * and set these fields.
	 */
	id_node = new_node(AS_SIMPLE_NAME);
	id_node->links.val = IND(n);
	set_span(id_node,LOC(n));
}


/* The following functions are for passing to check_pragmas */

int immediate_decl_pragmas(int p)				/*;immediate_decl_pragmas*/
{
#ifdef PDEBUG
	printf("enter immediate_decl pragmas %d %d\n",p,isimmediate_decl_pragma[p]);
#endif
	return(isimmediate_decl_pragma[p]);
}

int compilation_pragmas(int p)					/*;compilation_pragmas*/
{
#ifdef PDEBUG
	printf("enter compilation pragmas %d %d\n",p,iscompilation_pragma[p]);
#endif
	return(iscompilation_pragma[p]);
}

int after_libunit_pragmas(int p)				/*;after_libunit_pragmas*/
{
#ifdef PDEBUG
	printf("enter after_libunit pragmas %d %d\n",p,isafter_libunit_pragma[p]);
#endif
	return(isafter_libunit_pragma[p]);
}

int task_pragmas(int p)							/*;task_pragmas*/
{
#ifdef PDEBUG
	printf("enter istask pragmas %d %d\n",p,istask_pragma[p]);
#endif
	return(istask_pragma[p]);
}

int task_repr_pragmas(int p)					/*;task_repr_pragmas*/
{
#ifdef PDEBUG
	int r;
	r =(istask_pragma[p] || isrepr_pragma[p]);
	printf("enter task_repr pragmas %d %d\n",p,r);
#endif
	return(istask_pragma[p] || isrepr_pragma[p]);
}

int context_pragmas(int p)						/*;context_pragmas*/
{
#ifdef PDEBUG
	printf("enter context pragmas %d %d\n",p,iscontext_pragma[p]);
#endif
	return(iscontext_pragma[p]);
}

int null_pragmas(int i)									/*;null_pragmas*/
{
#ifdef PDEBUG
	printf("enter null pragmas \n");
#endif
	return(i = 0);
}


void check_choices(struct ast *alt_node, char *source)	/*;check_choices*/
{
	struct two_pool *others_indices = (struct two_pool *)0, 
	*choice_list, *last_alt_list;
	struct ast *last_alt = (struct ast *) 0;
	int choice_flag = 0;

	LLOOPTOP(alt_node->links.list,tmp)
	    if (tmp->val.node->kind != AS_PRAGMA) {
			choice_list = (tmp->val.node->links.subast)[0]->links.list;
			if (choice_list->link != choice_list)   /* cannot be NULL */
				LLOOPTOP(choice_list,tmp2)
			    	if (tmp2->val.node->kind == AS_OTHERS
					  || tmp2->val.node->kind == AS_OTHERS_CHOICE)
					{
						char msg[90];

						sprintf(msg,"The choice OTHERS must appear alone in %s",
						  source);
						syntax_err(SPAN(tmp2->val.node),msg);
						choice_flag = 1;
						break;
					}
				LLOOPBOTTOM(tmp2)
		   	if (!choice_flag) {
				if (choice_list->link->val.node->kind == AS_OTHERS
				  || choice_list->link->val.node->kind == AS_OTHERS_CHOICE)
					others_indices = concatl(others_indices,
					  initlist(tmp->val.node));
			}
			else
				choice_flag = 0;
			last_alt_list = tmp;
		}
	LLOOPBOTTOM(tmp)
	last_alt = last_alt_list->val.node;
	LLOOPTOP(others_indices,tmp)
	    {
		struct ast *choice;
		char msg[90];

		if (tmp->val.node == last_alt)
			continue;
		choice = (tmp->val.node->links.subast)[0]->links.list->link->val.node;
		sprintf(msg,"The choice OTHERS must appear last in %s",source);
		syntax_err(SPAN(choice),msg);
	}
	LLOOPBOTTOM(tmp)
	if (others_indices != (struct two_pool *)0 )
		TFREE(others_indices->link,others_indices);
}

struct two_pool *remove_duplicate_labels(struct two_pool *label_list)
											/*;remove_duplicate_labels*/
{
	struct two_pool *new_label_list = (struct two_pool *)0,
	*label_id_set = (struct two_pool *)0;
	struct ast *node, *label;

	LLOOPTOP(label_list,tmp)
	    if ((node = tmp->val.node)->kind == AS_SIMPLE_NAME) {
			if (in_label_set(node,label_id_set))
				syntax_err(SPAN(node),"Duplicate label name");
			else {
				/* new_label_list = concatl(new_label_list,initlist(node)); */
				label_id_set = concatl(label_id_set,initlist(node));
			}
			new_label_list = concatl(new_label_list,initlist(node));
		}
		else
		LLOOPTOP(node->links.list,tmp2)
		    label = tmp2->val.node;
		if (in_label_set(label,label_id_set))
			syntax_err(SPAN(label),"Duplicate label name");
		else
			label_id_set = concatl(label_id_set,initlist(label));
		LLOOPBOTTOM(tmp2)
	LLOOPBOTTOM(tmp)
	if (label_id_set != (struct two_pool *)0)
		TFREE(label_id_set->link,label_id_set);
	if (label_list != (struct two_pool *)0)
		TFREE(label_list->link,label_list);
	return(new_label_list);
}

static int in_label_set(struct ast *label, struct two_pool *label_set)
														/*;in_label_set*/
{
	int val = label->links.val;

	LLOOPTOP(label_set,tmp)
	    if (tmp->val.node->links.val == val)
			return(1);
	LLOOPBOTTOM(tmp)
	return(0);
}

void ins_as_line_no(struct ast *node)				/*;ins_as_line_no*/
{
	/* insert as_line_no nodes before each item in declarative/stmt list */
	struct two_pool *dec_list,
	*prev,*bottom;
	struct ast *line_node;
	struct tok_loc *line_node_span;


	if (node -> links.list != (struct two_pool *)0) {

		dec_list = bottom = node -> links.list;
		do {
			prev = dec_list;
			dec_list = dec_list -> link;

			line_node = new_node (AS_LINE_NO);
			line_node_span = get_left_span(dec_list->val.node);
			line_node -> links.val = line_node_span->line;
			set_span(line_node,line_node_span);
			/* Insert a new node with the AS_LINE_NO between dec_list and its 
					predecessor */
			prev -> link = initlist (line_node) ;
			prev->link->link = dec_list;
		} while (dec_list != bottom);
	}
}

void end_as_line_no(struct ast *list_node, struct prsstack *next_token)
													/*;end_as_line_no*/
{
	/* add an as_line_no node to end of statement list this is the line
	 * number of the token following the sequence of statements
	 */

	struct two_pool * last, * first;
	struct ast	    * line_node;

	if ( (last = list_node->links.list) != (struct two_pool *)0) {
		first = last->link;
		line_node = new_node (AS_LINE_NO);
		line_node->links.val = next_token->ptr.token->loc.line ;
		set_span(line_node,make_span(line_node->links.val,
		  next_token->ptr.token->loc.col));
		last->link = initlist(line_node);
		last->link->link = first;
		list_node->links.list = last->link;
	}
}

#define LABELSMAPSIZE 50

struct labelsmap {
	struct ast *node;
	struct two_pool *list;
	struct labelsmap *link;
};

struct labelsmap *nodetolabelstable[LABELSMAPSIZE]; /* Table for Labels map */
/* List of free label structures */
static struct labelsmap *deadlabels = (struct labelsmap *)0;

unsigned long labelshash(struct ast *node)			/*;labelshash*/
{
	/* The hash function from nodes to integers */
	return( ((unsigned long) node) % LABELSMAPSIZE);
}

void newlabels(struct ast *node, struct two_pool *list)		/*;newlabels*/
{
	/* Add node to the map, and initialize its labels list to list.
	 * Storage allocation is done using malloc/free structure list.
	 */

	int pos;
	struct labelsmap *labelnode;

	pos = (int)labelshash(node);
	if (deadlabels == (struct labelsmap *)0)
		labelnode = (struct labelsmap *)malloc(sizeof(struct labelsmap));
	else {
		labelnode = deadlabels;
		deadlabels = deadlabels->link;
	}
	labelnode->link = nodetolabelstable[pos];
	nodetolabelstable[pos] = labelnode;
	labelnode->node = node;
	labelnode->list = list;
}

struct two_pool *getlabels(struct ast *node)				/*;getlabels*/
{
	/* Return the list of labels corresponding to a given node. If
	 * The map is not defined for a node, NULL is returned.
	 */

	struct labelsmap *tmp;

	for (tmp = nodetolabelstable[labelshash(node)];
	  tmp != (struct labelsmap *)0 && tmp->node != node; tmp = tmp->link);
	return((tmp == (struct labelsmap *)0) ? (struct two_pool *)0 : tmp->list);
}

void erase_labels(struct ast *node)						/*;erase_labels*/
{
	/* Remove a node from the labels map, freeing the structure used for
	 * that node's labels.
	 */

	struct labelsmap *tmp, *last;
	int pos;

	pos = (int)labelshash(node);
	for (tmp = nodetolabelstable[pos], last = (struct labelsmap *)0; 
	  tmp != (struct labelsmap *)0 && tmp->node != node;
	  last = tmp, tmp = tmp->link);
	if (tmp == (struct labelsmap *)0)
		return;
	if (last == (struct labelsmap *)0)
		nodetolabelstable[pos] = tmp->link;
	else
		last->link = tmp->link;
	tmp->link = deadlabels;
	deadlabels = tmp;
	if (tmp->list != (struct two_pool *)0)
		TFREE(tmp->list->link,tmp->list);
}

struct two_pool *copylist(struct two_pool *list)			/*;copylist*/
{
	/* Copy a circular linked list of structs of type two_pool leaving
	 * the data of the nodes intact.
	 */
	struct two_pool *oldcurr, *newcurr, *top;

	if (list == (struct two_pool *)0)
		return((struct two_pool *)0);
	newcurr = top = TALLOC();
	oldcurr = list->link;
	top->val.node = oldcurr->val.node;
	while (oldcurr != list) {
		oldcurr = oldcurr->link;
		newcurr->link = TALLOC();
		newcurr = newcurr->link;
		newcurr->val.node = oldcurr->val.node;
	}
	newcurr->link = top;
	return(newcurr);
}

void free_labels()											/*;free_labels*/
{
	/* Remove all entries in the labels map. */
	int i;
	struct labelsmap *curr;

	for (i = 0; i < LABELSMAPSIZE; i++)
		if (nodetolabelstable[i] != (struct labelsmap *)0) {
			for (curr = nodetolabelstable[i]; curr->link!=NULL; curr=curr->link)
				if (curr->list != NULL)
					TFREE(curr->list->link,curr->list);
			curr->link = deadlabels;
			deadlabels = nodetolabelstable[i];
			nodetolabelstable[i] = NULL;
		}
}

#ifdef DEBUG
/* for debugging use */
void dump_labels(struct ast *node)							/*;dump_labels*/
{
	struct labelsmap *tmp;
	void zpnlist(struct two_pool *);

	for (tmp = nodetolabelstable[labelshash(node)];
	  tmp != NULL && tmp->node != node; tmp = tmp->link);
	zpnlist(tmp->list);
}
#endif 

static int is_pragma(int n)				 				/*;is_pragma*/
{
	/* Metaware miscompiles if:
	return (MIN_PRAGMA <= (n) && (n) <= MAX_PRAGMA);
     * so reorder first test until MetaWare compiler bug fixed
     */
	return ((n)>=MIN_PRAGMA  && (n) <= MAX_PRAGMA);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.