⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parser.cpp

📁 C-MINUS编译器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "parser.h"

/*************************************************
Copyright (C), 2002-2008, lonelyforest.
File name:     parser.cpp
Author:   林公玉(lonelyforest)
Version:  1.0
Date: 22-03-06 16:14
Description:   实现 parser.h 中的各个功能,修改于
    23-04-06 19:33
*************************************************/

// 
/**: TreeNode implementation ...
&
* author:	lonelyforest
* data:		2006.03.22
*/
//-----------------------------------------------------------------------------
TreeNode::TreeNode() : father( NULL ), sibling( NULL), lineno( 0 ),
bArr( false )
{
	for (int i = 0; i < MAX_CHILDREN; ++i)
	{
		child[i] = NULL;
	}
}

// destruction
TreeNode::~TreeNode()
{
	for (int i = 0; i < MAX_CHILDREN; ++i)
	{
		if (child[i]) delete child[i];
	}

	if (sibling ) delete sibling;
}

//-----------------------------------------------------------------------------
TreeNode* TreeNode::LastSibling()
{
	TreeNode* last = this;
	while (last->sibling) last = last->sibling;
	return last;
}

//-----------------------------------------------------------------------------
/**: parser tree implementation .. 
&
* author:	lonelyforest
* data:		2006.03.26
*/
Parser::Parser(const string &filename):treeFile(filename)
{ // filename needs extern name(.c);

	/* scan 可以直接声明为类成员,然后在类初始化之前构造,
	* 我都测试过,不过这样作为指针比较灵活,方便我作扩充,
	* 和修改不同的需要!
	* 也考虑过采用继承的方式,但是我担心那样会不会庞大不可靠? 呵呵
	* 缺乏高人指点, 凑活着作吧。
	*/
	scan = new Scanner(filename);
	
	
	m_program = NULL;
	indent = -1;
	traceParse = true;

	int pos = treeFile.rfind('.');
	treeFile.erase(pos, treeFile.size()-1);
	treeFile += ".st";	// syntax tree;
}

// destruction
Parser::~Parser()
{
	if (scan)		delete scan;
	if (m_program)	delete m_program;
}

// build parse tree
//-----------------------------------------------------------------------------
TreeNode* Parser::BuildSyntaxTree()
{
	m_program = program();
	return m_program;
}

/**: PrintTree(TreeNode* pNode);
&	get the file that printed the syntax tree;
* author:	lonelyforest
* data:		2006.03.26
*/
//-----------------------------------------------------------------------------
void Parser::getTreeFile()
{
	if (!m_program)
	{
		m_program = program();
	}

    if (traceParse) {
	   if ( !is_good() )
	   {
		outputMsg(-1, "Error(s) occur while parsing, stop printing syntax tree!");
	   }
	   else
	   {
		//outputMsg(-1, "successfully build the syntax tree, printing syntax tree now ...");

		out.open(treeFile.c_str());
		if (!out)
		{
			outputMsg(-1, "Create syntax tree file fail, syntax tree print stop now ... ");
		}
		else
		{
			PrintTree(m_program);
			sprintf(msg_temp, "Ok, treeFile has successfully save to  \"%s\"...", treeFile.c_str());
			outputMsg(-3,  msg_temp);   // -3 means Syntax tree file.
		}
		
		out.close();
	   }
    }
}


/**: PrintTree(TreeNode* pNode);
&
* author:	lonelyforest
* data:		2006.03.26
*/
//-----------------------------------------------------------------------------
void Parser::PrintTree(TreeNode* pNode)
{
	indent++;
	while (pNode != NULL) {
		for (int i  = 0; i < indent; ++i)
		{
			out << "\t";
		}

		switch (pNode->nodekind) {
			case funK:
				out << "Function declaration: "
					<< scan->key_word[(int)pNode->type].str
				    << " " <<pNode->name << endl;
				break;
			case varK:
				out << "Variable declaration: "
					<< scan->key_word[(int)pNode->type].str
					<<" " << pNode->name;
				if (pNode->bArr) out << "[" << pNode->iArrSize <<"] ";
				out  << endl;
				break;
			case paramK:
				out << "parameter: "
					<< scan->key_word[(int)pNode->type].str
					<< " "<< pNode->name ;
				if (pNode->bArr) out << "[]";
				out << endl;
				break;
			case stmtK:	// switch
				switch (pNode->kind.stmt){
					case readK:
						out << "call read(), args: " << endl;
						break;
					case writeK:
						out << "call write(), args:" << endl;
						break;
					case callK:
						out << "call " << pNode->name << "(), args:" << endl;
						break;
					case ifK:	out << "if" << endl;	break;
					case whileK: out<< "while"<<endl;	break;
					case returnK: out <<"return"<<endl; break;
					default:	out << "unknown node kind, maybe parser bug!" <<endl;
						break;
				} //  end of switch (pNode->kind.stmt)
				break;
			case expK:	// switch (pNode->kind.exp
				switch (pNode->kind.exp) {
					case OpK:
						out << "Op: " << pNode->name << endl;
						break;
					case ConstK:
						out << "const: " << pNode->name <<endl;
						break;
					case IDK:
						out << "ID: " << pNode->name;
						if (pNode->bArr) {
						    pNode = pNode->child[0];
							if (pNode) out << "[" << pNode->name  <<"]";
						}

						out << endl;
						break;
					default:
						out << "unkown node kind, maybe parser bug!" << endl;
						break;
				} // end of switch (pNode->kind.exp)
				break;
			default:
				out << "unkown node kind, maybe parser bug!" <<endl;
				break;
		} // end  switch (pNode->nodekind)

		for ( int k = 0; k < MAX_CHILDREN; ++k)
        	{
        		if (pNode->child[k] != NULL)
				PrintTree(pNode->child[k]);
        	}

		// 以前居然忘记了写这句, 差点吧我害死!
		pNode = pNode->sibling;
	} // end while

	--indent;
}


/**: help functions 
&
* author:	lonelyforest
* data:		2006.03.29
*/
//------------------------------------------------------------------------------
// create a new node
TreeNode* Parser::newNode(const NodeKind kind, const enum tokenType Type, 
						  const string &ID)
{
	TreeNode* temp = new TreeNode();
	temp->lineno = scan->lineno();
	temp->nodekind = kind;
	temp->type  = Type;
	temp->name  = ID;
	temp->scope = Scope;

	return temp;
}

// create a new statment node
TreeNode* Parser::newStmtNode(const StmtKind Kind, const string &Name)
{
	TreeNode *t = new TreeNode();
	t->lineno  = scan->lineno();
	t->nodekind = stmtK;
	t->kind.stmt = Kind;
	t->type		= k_NONE;
	t->name		= Name;
	t->scope	= Scope;

	return t;
}

// create a new expression node
TreeNode* Parser::newExpNode(const ExpKind Kind, const enum tokenType Type,
							 const string &Name)
{
	TreeNode *t = new TreeNode();
	t->lineno = scan->lineno();
	t->nodekind = expK;
	t->kind.exp = Kind;
	t->type		= Type;
	t->name		= Name;
	t->scope	= Scope;

	return t;
}

// get next token and check if its type is expected..
//-----------------------------------------------------------------------------
bool Parser::match(enum tokenType Type)
{
	cToken = scan->nextToken();
	return (cToken.type == Type);
}

// for the error recovery ...
void Parser::consumeUntil(const tokenType Type)
{
	while (cToken.type != Type && cToken.type != k_EOF)
		cToken = scan->nextToken();
}

void Parser::consumeUntil(const tokenType type1, const tokenType type2)
{
	while ( cToken.type != type1 && cToken.type != type2
		&& cToken.type != k_EOF)
		cToken = scan->nextToken();
}
//-----------------------------------------------------------------------------

/**: Grammar fuction implementations ...
&
* author:	lonelyforest
* data:		2006.03.29
*/
//-----------------------------------------------------------------------------

/**: 1. program -> delaration_list
&
* author:	lonelyforest
* data:		2006.03.30
*/
TreeNode* Parser::program()
{
	return declaration_list();
}

/**: 2. declaration-list → declaration-list declaration | declaration
&
* author:	lonelyforest
* data:		2006.03.30
*/
TreeNode* Parser::declaration_list()
{
	TreeNode *program = NULL,
		*last	= NULL,
		*temp	= NULL;
	cToken	= scan->nextToken();

	while (cToken.type != k_EOF)
	{
		if (cToken.type != k_INT && cToken.type != k_VOID
			&& cToken.type != SEMI)
		{
			scan->add_err();
			sprintf(msg_temp, "Syntax error: invalid type \'%s\'",
				cToken.str.c_str());
			outputMsg(scan->lineno(), msg_temp);
			consumeUntil(SEMI, RBRACE); // ';', '}'
		}
		else if ((temp = declaration()) != NULL)
		{
			if (!program)
			{
				program = temp;
				last = temp->LastSibling();
			}
			else
			{
				last->sibling = temp;
				last = temp->LastSibling();
			}
		}

		cToken = scan->nextToken();
	}

	return program;
}


/**: 3. declaration → var-declaration | fun-declaration
&
* author:	lonelyforest
* data:		2006.03.30
*/
//-----------------------------------------------------------------------------
TreeNode* Parser::declaration()
{
	Scope = "global";	// use global fun or var
	TreeNode* temp = NULL;
	tToken = cToken;
	cToken = scan->nextToken();
	iToken = cToken;

	if (iToken.type != k_ID)
	{
		scan->add_err();
		sprintf(msg_temp, "Syntax error: %s is a reserved token", iToken.str.c_str());
		outputMsg(scan->lineno(), msg_temp);
		consumeUntil(SEMI, RBRACE);
	}
	else
	{
		cToken = scan->nextToken(); // expected a '(', '[' or  ','
		if (cToken.type == LPARAN) 
		{  // '(' is fun declaration
			temp = fun_declaration();
		}
		else if (cToken.type == SEMI || cToken.type == LSQUARE
			|| cToken.type == COMMA)
		{
			temp = var_declaration();
		}
		else
		{
			scan->add_err();
			sprintf(msg_temp, "Syntax error: missing \';\' after indentifer %s",
				iToken.str.c_str());
			outputMsg(scan->lineno(), msg_temp);
			consumeUntil(SEMI, RBRACE);
		}
	}

	return temp;
}

/**: 4. var-declaration → type-specifier ID(,...); | type-specifier ID [ NUM ](,...);
&	 5. type-specifier → int | void
*
* author:	lonelyforest
* data:		2006.03.30
*/
//-----------------------------------------------------------------------------
TreeNode* Parser::var_declaration()
{ // now, cToken.str == ";", "," or "["
	TreeNode* temp = newNode(varK, tToken.type, iToken.str);

	if (cToken.type == LSQUARE)
	{ // array
		cToken = scan->nextToken(); // must NUM
		if (cToken.type != k_NUM)
		{
			scan->add_err();
			sprintf(msg_temp, 
				"Syntax error: missing array size in declaration of array %s[]",
				iToken.str.c_str());
			outputMsg(scan->lineno(), msg_temp);
			delete temp;
			consumeUntil(SEMI, RBRACE);	// error recovery in global declaration

			return NULL;
		}

		temp->bArr = true;
		temp->iArrSize = atoi(cToken.str.c_str());

		if (!match(RSQUARE))
		{ // need "]" 
			scan->add_err();
			sprintf(msg_temp, 
				"Syntax error: missing \']\' in declaration of array %s[]",
				iToken.str.c_str());
			scan->push();	// error recovery here
		}

		cToken = scan->nextToken(); // ";" or ","
	}

	if (cToken.type == COMMA)
	{
		iToken = cToken = scan->nextToken(); // next ID
		if (iToken.type != k_ID)
		{
			scan->add_err();
			sprintf(msg_temp, "Syntax error: %s is a reserved token", iToken.str.c_str());
			outputMsg(scan->lineno(), msg_temp);
			consumeUntil(SEMI, RBRACE);

			return temp;
		}

		cToken = scan->nextToken(); // expected ";", ",", "["
		if (cToken.type == SEMI || cToken.type == COMMA 
			|| cToken.type == LSQUARE)
		{
			temp->sibling = var_declaration();
		}
		else
		{
			scan->add_err();
			sprintf(msg_temp, 
				"Syntax error: missing \';\' after indentifer \"%s\"",
				iToken.str.c_str());
			outputMsg(scan->lineno(), msg_temp);
			scan->push();
			return temp;
		}
	}
	else if (cToken.type != SEMI)
	{
		scan->add_err();
		outputMsg(scan->lineno(),
			"Syntax error: missing \';\' after declaration sequence");
		consumeUntil(SEMI, RBRACE);
	}

	return temp;
}


/**:  6. fun-declaration → type-specifier ID ( params )  compound-stmt
&
* author:	lonelyforest
* data:		2006.03.30
*/
TreeNode* Parser::fun_declaration()
{	// cToken.str == "(", tToken contains type_specifier, iToken contains ID
	TreeNode *temp = newNode(funK, tToken.type, iToken.str);
	Scope = iToken.str;	// update function scope now,
	TreeNode *p = NULL;

	p = temp->child[0] = params();

	if (p) p->father = temp;
	while (p && p->sibling)
	{
		p = p->sibling;
		p->father = temp;
	}

	scan->push();

	if (!match(RPARAN))
	{
		scan->add_err();
		sprintf(msg_temp, 
			"Syntax error: missing \')\' in function %s(...) declaration",
			iToken.str.c_str());
		outputMsg(scan->lineno(), msg_temp);
		scan->push();
	}

	// compound statements
	p = temp->child[1] = compound_stmt();
	if (p) p->father = temp;
	while (p && p->sibling)
	{
		p = p->sibling;
		p->father = temp;
	}

	return temp;
}

/**: 7. params → params-list | void
&	 8. param-list→ param-list, param | param
&	 9. param→ type-specifier ID | type-specifier ID [ ]
* author:	lonelyforest
* data:		2006.03.30
*/
TreeNode* Parser::params()
{
	TreeNode *first = NULL;
	TreeNode *temp  = NULL;
	tToken = cToken = scan->nextToken();

	if (cToken.type == RPARAN)
	{
		scan->push();
		return temp; // NULL
	}

	if (tToken.type == k_VOID)
	{
		if (match(RPARAN))
		{ 
			scan->push();
			return temp;	// NULL
		}
		else
		{
			scan->push();	// not ")"
		}
	}

	while (tToken.type == k_INT || tToken.type == k_VOID)
	{
		iToken = cToken = scan->nextToken();
		if (iToken.type != k_ID)
		{
			scan->add_err();
			sprintf(msg_temp, 
				"Syntax error: invalid parameter \"%s\"",
				iToken.str.c_str());
			outputMsg(scan->lineno(), msg_temp);
		}
		else
		{
			temp = newNode(paramK, tToken.type, iToken.str);
			temp->sibling = first;
			first = temp;
		}

		cToken = scan->nextToken();
		if (cToken.type == LSQUARE)
		{
			temp->bArr = true;
			if (!match(RSQUARE))
			{
				scan->add_err();
				outputMsg(scan->lineno(), "Syntax error: arrar parameter missing \']\'");
				consumeUntil(COMMA, RPARAN);
			}
			else
			{
				cToken = scan->nextToken();	// ','
			}
		}

		if (cToken.type == RPARAN)	break; // ')'
		else if (cToken.type == COMMA) // ','
		{
			tToken = cToken = scan->nextToken();
		}
		else
		{
			break;
		}
	}

	scan->push();	// next is ')'

	return first;
}

/**:   10. compound-stmt → { local-declarations statement-list }
&
* author:	lonelyforest
* data:		2006.03.30
*/
TreeNode* Parser::compound_stmt()
{
	TreeNode *first = NULL,
		*last	= NULL,
		*temp	= NULL;
	bool noBraces = false;

	if (!match(LBRACE))
	{	// match "{"
		noBraces = true;
		scan->push();
	}

	// local-declarations
	while (true)
	{
		tToken = cToken = scan->nextToken();
		if (cToken.type == k_INT || cToken.type == k_VOID)
		{
			temp = local_declarations();
		}
		else
		{
			scan->push();
			break;
		}

		if (noBraces)	return temp;
		if (temp)
		{
			if (!first)
			{
				first = temp;
				last = temp->LastSibling();
			}
			else
			{
				last->sibling = temp;
				last = temp->LastSibling();
			}
		}
	}

	cToken = scan->nextToken();
	while (true)
	{
		temp = NULL;
		if (cToken.type == RBRACE)
		{
			if (noBraces)
			{
				scan->add_err();
				outputMsg(scan->lineno(), "Syntax error: unpaired \'}\'");
			}

			break;
		}

		if (cToken.type == k_EOF)
		{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -