Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / MFC

Another Enum Viewer

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
22 Oct 20015 min read 82.8K   1.3K   19  
An article on the usage and design of another Enum Viewer
/*
 * PCCTSAST.C
 *
 * SOFTWARE RIGHTS
 *
 * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public
 * domain.  An individual or company may do whatever they wish with
 * source code distributed with SORCERER or the code generated by
 * SORCERER, including the incorporation of SORCERER, or its output, into
 * commerical software.
 * 
 * We encourage users to develop software with SORCERER.  However, we do
 * ask that credit is given to us for developing SORCERER.  By "credit",
 * we mean that if you incorporate our source code into one of your
 * programs (commercial product, research project, or otherwise) that you
 * acknowledge this fact somewhere in the documentation, research report,
 * etc...  If you like SORCERER and have developed a nice tool with the
 * output, please mention that you developed it using SORCERER.  In
 * addition, we ask that this header remain intact in our source code.
 * As long as these guidelines are kept, we expect to continue enhancing
 * this system and expect to make other tools available as they are
 * completed.
 *
 * SORCERER 1.00B14 and ANTLR 1.33
 * Terence Parr
 * Parr Research Corporation
 * AHPCRC, University of Minnesota
 * 1992-1995
 */

#define ANTLR_SUPPORT_CODE

#include "PCCTSAST.h"
#include <stdarg.h>
#include <ctype.h>
//#include "SList.h"

               /* String Scanning/Parsing Stuff */

char *PCCTS_AST::scan_token_tbl[] = {
	"invalid",	/*	0 */
	"LPAREN",	/*	1 */
	"RPAREN",	/*	2 */
	"PERCENT",	/*	3 */
	"INT",		/*	4 */
	"COLON",	/*	5 */
	"POUND",	/*	6 */
	"PERIOD",	/*	7 */
};

void PCCTS_AST::
addChild(PCCTS_AST *t)
{
	if ( t==NULL ) return;
	PCCTS_AST *s = down();
	if ( s!=NULL )
	{
		while ( s->right()!=NULL ) s = s->right();
		s->setRight(t);
	}
	else
		this->setDown(t);
}

void PCCTS_AST::
lisp(FILE *f)
{
	if ( down() != NULL ) fprintf(f," (");
	lisp_action(f);
	if ( down()!=NULL ) down()->lisp(f);
	if ( down() != NULL ) fprintf(f," )");
	if ( right()!=NULL ) right()->lisp(f);
}

/* build a tree (root child1 child2 ... NULL)
 * If root is NULL, simply make the children siblings and return ptr
 * to 1st sibling (child1).  If root is not single node, return NULL.
 *
 * Siblings that are actually sibling lists themselves are handled
 * correctly.  For example #( NULL, #( NULL, A, B, C), D) results
 * in the tree ( NULL A B C D ).
 *
 * Requires at least two parameters with the last one being NULL.  If
 * both are NULL, return NULL.
 *
 * The down() and right() down/right pointers are used to make the tree.
 */
PCCTS_AST *PCCTS_AST::
make(PCCTS_AST *rt, ...)
{
	va_list ap;
	register PCCTS_AST *child, *sibling=NULL, *tail, *w;
	PCCTS_AST *root;

	va_start(ap, rt);
	root = rt;

	if ( root != NULL )
		if ( root->down() != NULL ) return NULL;
	child = va_arg(ap, PCCTS_AST *);
	while ( child != NULL )
	{
		/* find end of child */
		for (w=child; w->right()!=NULL; w=w->right()) {;}
		if ( sibling == NULL ) {sibling = child; tail = w;}
		else {tail->setRight(child); tail = w;}
		child = va_arg(ap, PCCTS_AST *);
	}
	if ( root==NULL ) root = sibling;
	else root->setDown(sibling);
	va_end(ap);
	return root;
}

/* The following push and pop routines are only used by ast_find_all() */

void PCCTS_AST::
_push(PCCTS_AST **st, int *sp, PCCTS_AST *e)
{
	(*sp)--;
	require((*sp)>=0, "stack overflow");
	st[(*sp)] = e;
}

PCCTS_AST *PCCTS_AST::
_pop(PCCTS_AST **st, int *sp)
{
	PCCTS_AST *e = st[*sp];
	(*sp)++;
	require((*sp)<=MaxTreeStackDepth, "stack underflow");
	return e;
}

/* Find all occurrences of u in t.
 * 'cursor' must be initialized to 't'.  It eventually
 * returns NULL when no more occurrences of 'u' are found.
 */
PCCTS_AST *PCCTS_AST::
ast_find_all(PCCTS_AST *u, PCCTS_AST **cursor)
{
	PCCTS_AST *sib;
	static PCCTS_AST *template_stack[MaxTreeStackDepth];
	static int tsp = MaxTreeStackDepth;
	static int nesting = 0;

	if ( *cursor == NULL ) return NULL;
	if ( *cursor!=this ) sib = *cursor;
	else {
		/* else, first time--start at top of template 't' */
		tsp = MaxTreeStackDepth;
		sib = this;
		/* bottom of stack is always a NULL--"cookie" indicates "done" */
		_push(template_stack, &tsp, NULL);
	}

keep_looking:
	if ( sib==NULL )	/* hit end of sibling list */
	{
		sib = _pop(template_stack, &tsp);
		if ( sib == NULL ) { *cursor = NULL; return NULL; }
	}

	if ( sib->type() != u->type() )
	{
		/* look for another match */
		if ( sib->down()!=NULL )
		{
			if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());
			sib=sib->down();
			goto keep_looking;
		}
		/* nothing below to try, try next sibling */
		sib=sib->right();
		goto keep_looking;
	}

	/* found a matching root node, try to match what's below */
	if ( match_partial(sib, u) )
	{
		/* record sibling cursor so we can pick up next from there */
		if ( sib->down()!=NULL )
		{
			if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());
			*cursor = sib->down();
		}
		else if ( sib->right()!=NULL ) *cursor = sib->right();
		else *cursor = _pop(template_stack, &tsp);
		return sib;
	}

	/* no match, keep searching */
	if ( sib->down()!=NULL )
	{
		if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right());
		sib=sib->down();
	}
	else sib = sib->right();	/* else, try to right if zip below */
	goto keep_looking;
}

/* are two trees exactly alike? */
int PCCTS_AST::
match(PCCTS_AST *u)
{
	PCCTS_AST *t = this;
	PCCTS_AST *sib;

	if ( u==NULL ) return 0;

	for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())
	{
		if ( sib->type() != u->type() ) return 0;
		if ( sib->down()!=NULL )
			if ( !sib->down()->match(u->down()) ) return 0;
	}
	return 1;
}

/* Is 'u' a subtree of 't' beginning at the root? */
int PCCTS_AST::
match_partial(PCCTS_AST *t, PCCTS_AST *u)
{
	PCCTS_AST *sib;

	if ( u==NULL ) return 1;
	if ( t==NULL ) if ( u!=NULL ) return 0; else return 1;

	for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())
	{
		if ( sib->type() != u->type() ) return 0;
		if ( sib->down()!=NULL )
			if ( !match_partial(sib->down(), u->down()) ) return 0;
	}
	return 1;
}

/* Walk the template tree 't' (matching against 'this'), filling in the
 * 'labels' array, and setting 'n' according to how many labels were matched.
 */
int PCCTS_AST::
scanmatch(ScanAST *t, PCCTS_AST **labels[], int *n)
{
	ScanAST *sib;
	PCCTS_AST *u = this;

	if ( u==NULL ) return 0;

	for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right())
	{
		/* make sure tokens match; token of '0' means wildcard match */
		if ( sib->type() != u->type() && sib->type()!=0 ) return 0;
		/* we have a matched token here; set label pointers if exists */
		if ( sib->label_num>0 )
		{
			require(labels!=NULL, "label found in template, but no array of labels");
			(*n)++;
			*(labels[sib->label_num-1]) = u;
		}
		/* match what's below if something there and current node is not wildcard */
		if ( sib->down()!=NULL && sib->type()!=0 )
		{
			if ( sib->down()==NULL ) if ( u->down()!=NULL ) return 0; else return 1;
			if ( !u->down()->scanmatch(sib->down(), labels, n) ) return 0;
		}
	}
	return 1;
}

void PCCTS_AST::
insert_after(PCCTS_AST *b)
{
	PCCTS_AST *end;
	if ( b==NULL ) return;
	/* find end of b's child list */
	for (end=b; end->right()!=NULL; end=end->right()) {;}
	end->setRight(this->right());
	this->setRight(b);
}

void PCCTS_AST::
append(PCCTS_AST *b)
{
	PCCTS_AST *end;
	require(b!=NULL, "append: NULL input tree");
	/* find end of child list */
	for (end=this; end->right()!=NULL; end=end->right()) {;}
	end->setRight(b);
}

PCCTS_AST *PCCTS_AST::
tail()
{
	PCCTS_AST *end;
	/* find end of child list */
	for (end=this; end->right()!=NULL; end=end->right()) {;}
	return end;
}

PCCTS_AST *PCCTS_AST::
bottom()
{
	PCCTS_AST *end;
	/* find end of child list */
	for (end=this; end->down()!=NULL; end=end->down()) {;}
	return end;
}

PCCTS_AST *PCCTS_AST::
cut_between(PCCTS_AST *a, PCCTS_AST *b)
{
	PCCTS_AST *end, *ret;
	if (a==NULL||b==NULL) return NULL;
	/* find node pointing to b */
	for (end=a; end->right()!=NULL&&end->right()!=b; end=end->right())
		{;}
	if (end->right()==NULL) return NULL; //ast_cut_between: a,b not connected
	end->setRight(NULL);	/* don't want it point to 'b' anymore */
	ret = a->right();
	a->setRight(b);
	return ret;
}

#ifdef NOT_YET
SList *PCCTS_AST::
to_slist()
{
	SList *list = new SList;
	PCCTS_AST *p;

	for (p=this; p!=NULL; p=p->right())
	{
		list->add(p);
	}
	return list;
}
#endif

void PCCTS_AST::
tfree()
{
	PCCTS_AST *t = this;
    if ( t->down()!=NULL ) t->down()->tfree();
    if ( t->right()!=NULL ) t->right()->tfree();
    delete t;
}

int PCCTS_AST::
nsiblings()
{
	PCCTS_AST *t = this;
	int n=0;

	while ( t!=NULL )
	{
		n++;
		t = t->right();
	}
	return n;
}

PCCTS_AST *PCCTS_AST::
sibling_index(int i)
{
	PCCTS_AST *t = this;
	int j=1;
	require(i>0, "sibling_index: i<=0");

	while ( t!=NULL )
	{
		if ( j==i ) return t;
		j++;
		t = t->right();
	}
	return NULL;
}

/* Assume this is a root node of a tree--
 * duplicate that node and what's below; ignore siblings of root node.
 */
PCCTS_AST *PCCTS_AST::
deepCopy()
{
	PCCTS_AST *u = this->shallowCopy();
	if ( down()!=NULL ) u->setDown(down()->deepCopy());
	return u;
}

/* Copy all nodes including siblings of root. */
PCCTS_AST *PCCTS_AST::
deepCopyBushy()
{
	PCCTS_AST *u = this->shallowCopy();
	/* copy the rest of the tree */
	if ( down()!=NULL ) u->setDown(down()->deepCopy());
	if ( right()!=NULL ) u->setRight(right()->deepCopy());
	return u;
}

void PCCTS_AST::
scanast_free(ScanAST *t)
{
    if ( t == NULL ) return;
    scanast_free( t->down() );
    scanast_free( t->right() );
    free( t );
}

/*
 * scan
 *
 * This function is like scanf(): it attempts to match a template
 * against an input tree.  A variable number of tree pointers
 * may be set according to the '%i' labels in the template string.
 * For example:
 *
 *   t->ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )",
 *            &w, &x, &y, &z);
 *
 * Naturally, you'd want this converted from
 *
 *	 t->ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )",
 *			  &w, &x, &y, &z);
 *
 * by SORCERER.
 *
 * This function call must be done withing a SORCERER file because SORCERER
 * must convert the token references to the associated token number.
 *
 * This functions parses the template and creates trees which are then
 * matched against the input tree.  The labels are set as they are
 * encountered; hence, partial matches may leave some pointers set
 * and some NULL.  This routines initializes all argument pointers to NULL
 * at the beginning.
 *
 * This function returns the number of labels matched.
 */
int PCCTS_AST::
ast_scan(char *templ, ...)
{
	va_list ap;
	ScanAST *tmpl;
	int n, i, found=0;
	PCCTS_AST ***label_ptrs=NULL;

	va_start(ap, templ);

	/* make a ScanAST tree out of the template */
	tmpl = stringparser_parse_scanast(templ, &n);

	/* make an array out of the labels */
	if ( n>0 )
	{
		label_ptrs = (PCCTS_AST ***) calloc(n, sizeof(PCCTS_AST **));
		require(label_ptrs!=NULL, "scan: out of memory");
		for (i=1; i<=n; i++)
		{
			label_ptrs[i-1] = va_arg(ap, PCCTS_AST **);
			*(label_ptrs[i-1]) = NULL;
		}
	}

	/* match the input tree against the template */
	scanmatch(tmpl, label_ptrs, &found);

	scanast_free(tmpl);
	free(label_ptrs);

	return found;
}

ScanAST *PCCTS_AST::
new_scanast(int tok)
{
    ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST));
    if ( p == NULL ) {fprintf(stderr, "out of mem\n"); exit(EXIT_FAILURE);}
	p->_token = tok;
	return p;
}

ScanAST *PCCTS_AST::
stringparser_parse_scanast(char *templ, int *num_labels)
{
	StringLexer lex;
	StringParser parser;
	ScanAST *t;

	stringlexer_init(&lex, templ);
	stringparser_init(&parser, &lex);
	t = stringparser_parse_tree(&parser);
	*num_labels = parser.num_labels;
	return t;
}

void PCCTS_AST::
stringparser_match(StringParser *parser, int token)
{
	if ( parser->token != token ) panic("bad tree in scan()");
}

/*
 * Match a tree of the form:
 *		(root child1 child2 ... childn)
 * or,
 *		node
 *
 * where the elements are integers or labeled integers.
 */
ScanAST *PCCTS_AST::
stringparser_parse_tree(StringParser *parser)
{
	ScanAST *t=NULL, *root, *child, *last;

	if ( parser->token != __POUND )
	{
		return stringparser_parse_element(parser);
	}
	stringparser_match(parser,__POUND);
	parser->token = stringscan_gettok(parser->lexer);
	stringparser_match(parser,__LPAREN);
	parser->token = stringscan_gettok(parser->lexer);
	root = stringparser_parse_element(parser);
	while ( parser->token != __RPAREN )
	{
		child = stringparser_parse_element(parser);
		if ( t==NULL ) { t = child; last = t; }
		else { last->_right = child; last = child; }
	}
	stringparser_match(parser,__RPAREN);
	parser->token = stringscan_gettok(parser->lexer);
	root->_down = t;
	return root;
}

ScanAST *PCCTS_AST::
stringparser_parse_element(StringParser *parser)
{
	static char ebuf[100];
	int label = 0;

	if ( parser->token == __POUND )
	{
		return stringparser_parse_tree(parser);
	}
	if ( parser->token == __PERCENT )
	{
		parser->token = stringscan_gettok(parser->lexer);
		stringparser_match(parser,__INT);
		label = atoi(parser->lexer->text);
		parser->num_labels++;
		if ( label==0 ) panic("%%0 is an invalid label");
		parser->token = stringscan_gettok(parser->lexer);
		stringparser_match(parser,__COLON);
		parser->token = stringscan_gettok(parser->lexer);
		/* can label tokens and wildcards */
		if ( parser->token != __INT && parser->token != __PERIOD )
			panic("can only label tokens");
	}
	if ( parser->token == __INT )
	{
		ScanAST *p = new_scanast(atoi(parser->lexer->text));
		parser->token = stringscan_gettok(parser->lexer);
		p->label_num = label;
		return p;
	}
	if ( parser->token == __PERIOD )
	{
		ScanAST *p = new_scanast(0);	/* token of 0 is wildcard */
		parser->token = stringscan_gettok(parser->lexer);
		p->label_num = label;
		return p;
	}
	sprintf(ebuf, "mismatch token in scan(): %s", scan_token_str(parser->token));
	panic(ebuf);
	return NULL;
}

void PCCTS_AST::
stringparser_init(StringParser *parser, StringLexer *input)
{
	parser->lexer = input;
	parser->token = stringscan_gettok(parser->lexer);
	parser->num_labels = 0;
}

void PCCTS_AST::
stringlexer_init(StringLexer *scanner, char *input)
{
	scanner->text[0]='\0';
	scanner->input = input;
	scanner->p = input;
	stringscan_advance(scanner);
}

void PCCTS_AST::
stringscan_advance(StringLexer *scanner)
{
	if ( *(scanner->p) == '\0' ) scanner->c = __StringScanEOF;
	scanner->c = *(scanner->p)++;
}

int PCCTS_AST::
stringscan_gettok(StringLexer *scanner)
{
	char *index = &scanner->text[0];
	static char ebuf[100];

	while ( isspace(scanner->c) ) { stringscan_advance(scanner); }
	if ( isdigit(scanner->c) )
	{
		int tok = __INT;
		while ( isdigit(scanner->c) ) {
			*index++ = scanner->c;
			stringscan_advance(scanner);
		}
		*index = '\0';
		return tok;
	}
	switch ( scanner->c )
	{
		case '#' : stringscan_advance(scanner); return __POUND;
		case '(' : stringscan_advance(scanner); return __LPAREN;
		case ')' : stringscan_advance(scanner); return __RPAREN;
		case '%' : stringscan_advance(scanner); return __PERCENT;
		case ':' : stringscan_advance(scanner); return __COLON;
		case '.' : stringscan_advance(scanner); return __PERIOD;
		case '\0' : return __StringScanEOF;
		case __StringScanEOF : return __StringScanEOF;
		default  :
			sprintf(ebuf, "invalid char in scan: '%c'", scanner->c);
			panic(ebuf);
	}
	return __StringScanEOF;	// never reached
}

char *PCCTS_AST::
scan_token_str(int t)
{
	if ( VALID_SCAN_TOKEN(t) ) return scan_token_tbl[t];
	else if ( t==__StringScanEOF ) return "<end-of-string>";
	else return "<invalid-token>";
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions