Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source libSC hier parse.c
Document Actions

parse.c

by Michael L Powell last modified 2007-01-26 03:24

Click here to get the file

Size 12.1 kB - File type text/plain

File contents

/*ident	"@(#)hier:parse.c	3.1" */
/******************************************************************************
*
* C++ Standard Components, Release 3.0.
*
* Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc.
* Copyright (c) 1988, 1989, 1990 AT&T.  All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System
* Laboratories, Inc.  The copyright notice above does not evidence
* any actual or intended publication of such source code.
*
******************************************************************************/

#ifdef __GNUG__
#pragma implementation "Map.h"
#endif
#include "hier.h"
#include <Map.h>
#include <setjmp.h>

//Mapdeclare(String,TokenType)
//Mapimplement(String,TokenType)
#ifdef __GNUG__
template class Map<String,TokenType>;
#endif

static Map<String,TokenType> aggtyp;
static jmp_buf beginning;
static int nErrors = 0;
static int inRootFile;  // are we in the root file?

// see my comment in ./hier
static String rootFileName;
static int getRootFileName;

static void classHead();
static void templateHead();
static void baseList();
static void baseUnit();
static void parseAFragment();
static int interesting(TokenType);
static void advToMatchingAppendingTo(String &);
static void advToMatchingCollectOnlyClass(String &);

ostream& operator<<(ostream& os, Protection p) 
{
	switch (p)
	{
		case Private: os << "private"; break;
		case Protected: os << "protected"; break;
		case Public: os << "public"; break;
	}
	return os;
}

int parse()
{
	inRootFile = 1;
	rootFileName.make_empty();
	getRootFileName = 1;
	while (TOK != EOFTOK)
	{
		if (setjmp(beginning)) 
		{
			/* parsing returns here when the string is not in our subgrammar */
		}
		else
		{
			while (!interesting(TOK))
				ADV;
			if (TOK != EOFTOK)
				parseAFragment();
		}
	}
	return nErrors;
}

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

// note that template is always interesting
// since keyword "class" inside  <> must be consumed. 
static int interesting(TokenType t)
{
	return (t == POUND || 
		t == EOFTOK || 
		(((t == CLASS && doClasses) || 
		  (t == STRUCT && doStructs) || 
		  (t == TEMPLATE && doClasses) ||
		  (t == UNION && doUnions)) 
			&& (inRootFile || !rootFileOnly)));
}

/* advance to t or eof.  returns true if the former.
*/
static int advTo(TokenType t)
{
	TokenType tok;
	while (((tok=TOK) != t) && (tok != EOFTOK))
		ADV;
	return (tok == t);
}

static void cppline()
{
	assert (TOK == POUND);
	lexer->newlineIsToken();
	ADV;
	if (TOK == LITINT)
	{
		Litint litint;
		lexer->get(litint);
				// The -1 counteracts the newline coming up at the end of this preprocessor line.
		lexer->setLineno(litint.intval - 1);  
		ADV;
		if (TOK == LITSTRING)
		{
			Litstring litstring;
			lexer->get(litstring);
			lexer->setFilename(litstring.thestring);
//cerr << "rootFileName " << rootFileName << ", new name " << litstring.thestring << endl;
			if (getRootFileName)
			{
				getRootFileName = 0;
				rootFileName = litstring.thestring;
			}
			else 
			{
				inRootFile = (litstring.thestring == rootFileName);
			}
			ADV;
		}			
	}
	advTo(NL);
	lexer->newlineIsntToken();
	ADV;
}

static void parseAFragment()
{
	switch (TOK) {
	case CLASS: case STRUCT: case UNION:
		classHead();
	break;
	case POUND:
		cppline();
	break;
	case TEMPLATE:
		templateHead();
	break;
	default:
	//cast TOK, some compiler complains ambiguity with <<(o, Protection )
		cerr << "Token type is " << (int)(TOK) << endl;
		assert(0);
	break;
	}
}

static inline void fail()
{
	lexer->melt();
	longjmp(beginning, 1);
}

static void message(char *prefix, char *mess)
{
	cerr << prefix << ": line " << (lexer->emptyWindow()? 1 : LINENO) << " " << lexer->filename();
	if (mess)
		cerr << ": " << mess;
	cerr << endl;
}

/*
static void sorry(char *mess)
{
	nErrors++;
	message("Sorry, not implemented", mess);
	fail();
}
*/

void syntaxError(char *mess)
{
	nErrors++;
	message("Syntax error", mess);
	fail();
}

void syntaxErrorNoFailure(char *mess)
{
	nErrors++;
	message("Syntax error", mess);
}

/*
static inline void warning(char *mess)
{
	message("Warning", mess);
}
*/

static inline void match(TokenType t)
{
	if (TOK == t)
		ADV;
	else
		syntaxError(NULL);
}

/*
static inline void matchOptional(TokenType t)
{
	if (TOK == t)
		ADV;
}
*/

struct lws {
	const char *s;
	int len;
};

static const lws 
dagkeyword[] = {
	"draw", 4,
	"width", 5,
	"height", 6,
	"as", 2,
	"edge", 4,
	"from", 4,
	"to", 2,
	"path", 4,
	"backpath", 8,
	"backedge", 8,
	"weight", 6,
	"label", 5,
	"solid", 5,
	"dashed", 6,
	"dotted", 6,
	"invis", 5,
	"separate", 8,
	"minimum", 7,
	"maximum", 7,
	"rank", 4,
	"same", 4,
	"nodes", 5,
	"ranks", 5,
	"exactly", 7,
	"equally", 7,
	0, 0,
};

static int mytolower(char c) {
	if (isupper(c))
		return c - 'A' + 'a';
	return c;
}

static int case_insensitive_equal(const char* p, const char* q) {
	assert(strlen(p) == strlen(q));
	//assert(string pointed to by q is all lower case);
	while (*p != '\0') {
		if (mytolower(*p) != *q)
			return 0;
		++p;
		++q;
	}
	assert(*q == '\0');
	return 1;
}
	
static int isdagkeyword(const String &s) {
	const char *p = s;
	for (const lws *key = dagkeyword; key->len != 0; ++key) {
		if ((s.length() == key->len) && (case_insensitive_equal(p, key->s)))
			return 1;
	}
	return 0;
}

class Aggtag {
	String s;
	char isdagkey;
public:
	Aggtag() : isdagkey(0) {}
	Aggtag(const String &s_) : s(s_) { isdagkey = ::isdagkeyword(s_); }
	void operator=(const String &s_) { s = s_; isdagkey = ::isdagkeyword(s_); }
	const String & getString() const { return s; }
	int isdagkeyword() const { return isdagkey; }
};

ostream & operator<<(ostream &os, const Aggtag &a) 
{
	// always put those quotes, since dag will probably
	// choke on nested and parameterized base class names
	//if (a.isdagkeyword()) 
		// that extra space causes dag not to treat it as a keyword
		//              |
		//               ------------
		//                           |
		//                           v
		os << '\"' << a.getString() << " \"";
	return os;
}

static void emitDrawCommand(const Aggtag &tag, TokenType agg)
{
	assert(agg == CLASS || agg == UNION || agg == STRUCT ||agg == TEMPLATE);
	if (agg == STRUCT)
		*dagout << "draw " << tag << " as Box;\n";
	else if (agg == UNION)
		*dagout << "draw " << tag << " as Diamond;\n";
}

static void emitEdge(const Aggtag &from, const Aggtag &to, Protection prot, int isvirtual)
{
	if (asciiOutput)
	{
		*asciiout << to.getString() << ' ' << prot << ' ' << from.getString();
		if (isvirtual)
			*asciiout << " virtual";
	}
	if (backwardEdges)
		*dagout << to << ' ' << from;
	else
		*dagout << from << ' ' << to;
	if (diffInher)
	{
		if (prot != Public)
			*dagout << " dashed";
		if (isvirtual)		
			*dagout << " label \"virtual\"";
	}
	*dagout << ';';
	if (whereFrom)
	{
		*dagout << "\t# " << lexer->lineno() << " \"" << lexer->filename() << '\"';
		if (asciiOutput)
			*asciiout << "\t# " << lexer->lineno() << " \"" << lexer->filename() << '\"';
	}
	if (asciiOutput)
		*asciiout << endl;
	*dagout << '\n';
}

static Aggtag currentTag;
static TokenType currentTagAgg;

static void classHead()
{
	assert (TOK == CLASS || TOK == STRUCT || TOK == UNION);
	currentTagAgg = TOK;
	ADV;
	if (TOK == LC)
	{
		ADV;
	}
	else
	{
		currentTag = LEXEME;
		if (diffAggs && !isolateds)  // then we have to mess with the map.
		{
			aggtyp[currentTag.getString()] = currentTagAgg;
		}
		match(ID);
		if (TOK == COLON)
		{
			baseList();
			match(LC);
		}
		else
		{
			// LC or anything else
			ADV;
		}
		if (diffAggs && isolateds)	// then we don't have to mess with the map.
		{
			emitDrawCommand(currentTag, currentTagAgg);
		}
		if (isolateds)
		{
			if (asciiOutput)
				*asciiout << currentTag << endl;
			*dagout << currentTag << ";\n";
		}
	}
}

// consumed <>, adv to the word "class", call baseList()
// template is always remembered as it is. and treated similar to class
static void templateHead()
{
	String	tempName;
	
	currentTagAgg = TOK;
	match(TEMPLATE);

	if (TOK == LANGLE)
	{
		// consume <class...>
		advToMatchingCollectOnlyClass(tempName);

		ADV;
		if( TOK != CLASS ) return;//reading function template
		ADV;

		currentTag = LEXEME;//name
		tempName =  LEXEME + tempName;

		if (diffAggs && !isolateds )
		{
			aggtyp[ currentTag.getString() ] = currentTagAgg;
		}
		match(ID);

		if( TOK == COLON )
		{
			currentTag = tempName;
			baseList();
			match(LC);
		}
		else
			// LC or anything else
			ADV;

		if( diffAggs && isolateds )
			//emitDrawCommand( currentTag, currentTagAgg );
			emitDrawCommand( tempName, currentTagAgg );

                if (isolateds)
                {
                        if (asciiOutput)
                                *asciiout << (Aggtag)tempName << endl;
                        *dagout << (Aggtag)tempName << ";\n";
                }
	}
	else
	{
		syntaxError("Missing <");
	}
}
static void baseList()		
{
	match(COLON);

	baseUnit();
	while (TOK == COMMA)
	{
		match(COMMA);
		baseUnit();
	}
}

static void foundAnInheritanceEdge(const String &basetype, Protection prot, int isvirtual)
{
	Aggtag base(basetype);
	emitEdge(base, currentTag, prot, isvirtual);
	if (diffAggs && !isolateds)  // then we have to mess with the map.
	{
		emitDrawCommand(currentTag, currentTagAgg);
		
		// for template, only use the name to index
		int	i = base.getString().index( '<' );

		if ( i != -1 )
		{
			String name = base.getString().chunk( 0, i );

			emitDrawCommand(base, aggtyp[ name ]);

		}
		else
		if (aggtyp.element(base.getString()))
		{
			emitDrawCommand(base, aggtyp[base.getString()]);
		}
		else
		{
			cerr << "hier: error: class " << currentTag.getString();
			cerr << " trying to inherit from undefined class " << base.getString() << '.' << endl;
		}
	}
}

static TokenType rightGroupTok(TokenType left)
{
        if (left == LP)
		return RP;
        else if (left == LC)
                return RC;
        else if (left == LS)
                return RS;
	else if (left == LANGLE)
		return RANGLE;
	assert(0);
	/* NOTREACHED */
	return ID;
}

// adv to the right grouping token and collect the dummy arg after class in the
// angle bracket
// also put the argument on a list
static void advToMatchingCollectOnlyClass(String &s)
{
        TokenType left = TOK;
        TokenType right = rightGroupTok(left);

        int depth = 1;
        while (depth > 0 && TOK != EOFTOK)
        {
		if( TOK != CLASS )
		{
			s += LEXEME;
		}

                ADV;
                if (TOK == left) depth++;
                else if (TOK == right) depth--;
		else if (TOK == LC)
			syntaxError("Missing >");  // hack.  currently this function is only called with TOK==<.
        }
        if (TOK == EOFTOK)
                syntaxError("Unexpected end of file: missing >");
	s += LEXWS;
	s += LEXEME;
}


// advance to the right grouping token matching the current token.
// while doing so, append lexemes and whitespace to the string s.
static void advToMatchingAppendingTo(String &s)
{
        TokenType left = TOK;
        TokenType right = rightGroupTok(left);

        int depth = 1;
        while (depth > 0 && TOK != EOFTOK)
        {
		s += LEXWS;
		s += LEXEME;
                ADV;

                if (TOK == left) depth++;
                else if (TOK == right) depth--;
		else if (TOK == LC)
			syntaxError("Missing >");  // hack.  currently this function is only called with TOK==<.
        }
        if (TOK == EOFTOK)
                syntaxError("Unexpected end of file: missing >");
	s += LEXWS;
	s += LEXEME;
}

static String collect_basetype_name()
{
	String s = LEXEME;
	match(ID);
	if (TOK == LANGLE)
	{
		advToMatchingAppendingTo(s);
		ADV;
	}
	while (TOK == QUAL)
	{
		s += "::";
		ADV;
		s += LEXEME;
		match(ID);
	}
	return s;
}		

static void baseUnit()
{
	int isvirtual = 0;
	Protection prot = (currentTagAgg == CLASS ||
			   currentTagAgg == TEMPLATE)? Private: Public;

	if (TOK == VIRTUAL)
	{
		isvirtual = 1;
		ADV;
	}
	switch (TOK) 
	{
		case PUBLIC:
			prot = Public;
			ADV;
			break;
		case PRIVATE:
			prot = Private;
			ADV;
			break;
		case PROTECTED:
			prot = Protected;
			ADV;
			break;
		default:
			break;
	}
	if (!isvirtual && (TOK == VIRTUAL))
	{
		isvirtual = 1;
		ADV;
	}
	if (TOK == ID)
	{
		String s = collect_basetype_name();
		foundAnInheritanceEdge(s, prot, isvirtual);
	}
}

« April 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: