Скачиваний:
21
Добавлен:
01.05.2014
Размер:
15.02 Кб
Скачать
#include <vector>

#include "SyntacticParser.hpp"
#include "TokenParser.hpp"
#include "Errors.hpp"


namespace Parser_impl {
    

PolizProgram* SyntaticParser::parse(std::istream& is) 
{
    prog = new PolizProgram;
    tokens = new TokenParser(is);
        
    tokens->getNextToken();    
    Program();
    
    delete tokens;
    return prog;
}

void SyntaticParser::Program()
{
	while (token()->type != TYPE_DELIM || token()->getLong() != T_EOF ) {
		if ( token()->type != TYPE_RES ) 
        	error("Wrong variable or function definition");
		if (token()->getLong() == T_VAR){
			currvarttable = &(prog->global);
			Vardef();
		} else
			Func();
	}
    checkProgram();
}

/**
 * needs currvarttable
 **/
void SyntaticParser::Vardef()
{
	assert_token(TYPE_RES, T_VAR);
	tokens->getNextToken();	
	if (token()->type != TYPE_RES)
		error("Wrong variable type, 'int' or 'float' expected");
	ElementTypes type;
	
	if (token()->getLong() == T_INT)
		type = INT;
	else if (token()->getLong() == T_FLOAT)
		type = FLOAT;
	else 
		error("Wrong variable type, 'int' or 'float' expected");
	
	tokens->getNextToken();
	
	assert_token(TYPE_ID, 0);
	if (currvarttable->contains(token()->str))
		error("Redeclaration of '" + token()->str +"'");
	currvarttable->put(token()->str, Variable(type, 0.0));		
	
	tokens->getNextToken();
	for(;;){
		if ( token()->type != TYPE_DELIM){
			break;
		} else if ( token()->getLong()!= T_COMMA )			
			break;	
			
		tokens->getNextToken();
		assert_token(TYPE_ID, 0);
		if (currvarttable->contains(token()->str))
			error("Redeclaration of '" + token()->str +"'");	
		currvarttable->put(token()->str, Variable(type, 0));
		tokens->getNextToken();
	}
}

void SyntaticParser::Func()
{
	if (token()->type != TYPE_RES)
		error("Wrong variable or function definition");
	
	Function fun;	
	std::string fun_name;
	
	if (token()->getLong() == T_VOID)
		fun.return_type = VOID;
	else if (token()->getLong() == T_INT)
		fun.return_type = INT;
	else if (token()->getLong() == T_FLOAT)
		fun.return_type = FLOAT;
	else
		error("Wrong function return type declaration, expected 'int', 'float' or 'void'");
	
	tokens->getNextToken();	
	assert_token(TYPE_ID, 0);
	fun_name = token()->str;
	
	tokens->getNextToken();
	assert_token(TYPE_DELIM, T_LBRACK);
	
	tokens->getNextToken();	
	bool expected = false;
	for(;;){
		
		if ( token()->type == TYPE_DELIM && token()->getLong() == T_RBRACK){
			if (expected)
				error("Wrong ';' before ')'"); 
			break;
		}
		
		expected =false;
		
		if (token()->type != TYPE_RES)
			error("Wrong argument type, 'int' or 'float' expected");
		
		Variable var;
		if (token()->getLong() == T_INT)
			var.type = INT;
		else if (token()->getLong() == T_FLOAT)
			var.type = FLOAT;
		else
			error("Wrong argument type, 'int' or 'float' expected");
		
		tokens->getNextToken();		
		assert_token (TYPE_ID, 0);
		
		if (fun.local.contains(token()->str))
			error("Redeclaration of '" + token()->str + "'");
		
		fun.local.put(token()->str, var);
		
		tokens->getNextToken();
		
		if (token()->type == TYPE_DELIM) {
			if (token()->getLong() == T_SEMIC){
				expected = true;
				tokens->getNextToken();
			} else if (token()->getLong() != T_RBRACK)
				error("Wrong delimitor, ';' is used to separate function arguments");				
		} else
			error("Wrong delimitor, ';' is used to separate function arguments");
						
	}	
	fun.args_count = fun.local.getSize();
	fun.name = fun_name;		
	tokens->getNextToken();
			
	if (token()->type == TYPE_DELIM && token()->getLong() == T_SEMIC){
		fun.declared = false;
		if (prog->functions.contains(fun_name)){			
			if (!fun.hasParamsEqualTo(prog->functions.get(fun_name)))
				error("Function redeclaration with different arguments or return value");
		} else {
			prog->functions.put(fun_name, fun);
		}
		tokens->getNextToken();
		return;
	} else {
		fun.declared = true;
		if (prog->functions.contains(fun_name)){
			Function& f = prog->functions.get(fun_name);
			if (!fun.hasParamsEqualTo(f))
				error("Function redeclaration with different arguments or return value");
			if (f.declared)
				error("Function already defined");
			f.declared = true;
			currfunc = &f;
		} else {
			int i = prog->functions.put(fun_name, fun);
			currfunc = &(prog->functions.get(i));
		}
		BL();
	}
}

/* *
 * needs currfunc
 * */
void SyntaticParser::BL()
{
	assert_token(TYPE_RES, T_BEGIN);
	
	tokens->getNextToken();
	
	if (!(token()->type == TYPE_RES && token()->getLong()==T_END)){
		ST();
	
		while ( token()->type == TYPE_DELIM && token()->getLong()==T_SEMIC){
			tokens->getNextToken();
			if (token()->type == TYPE_RES && token()->getLong()==T_END)
				error("';' can't stand before 'end'. ';' is statement separator, not statement end");
			ST();
		}
	}	 
	
	assert_token(TYPE_RES, T_END);
	
	tokens->getNextToken();
}


/* *
 * needs currfunc
 * */
void SyntaticParser::ST()
{
	
	if (token()->type == TYPE_RES) {
				
		long t = token()->getLong();		
		
		if (t == T_VAR){ 
			currvarttable = &(currfunc->local);
			Vardef();
			
		} else if (t == T_IF){
			
			tokens->getNextToken();
			E();
			
			int start = currfunc->code.size();						
			currfunc->code.push_back( PolizInstruction(TIfNot) );
			
			assert_token(TYPE_RES, T_THEN);			
						
			tokens->getNextToken();
			ST();
			
			int gt1 = currfunc->code.size();			
			
			if (token()->type == TYPE_RES && token()->getLong() == T_ELSE){				
				currfunc->code.push_back( PolizInstruction(TGoto) );
				++gt1;
				
				tokens->getNextToken();
				ST();
				
				(currfunc->code)[start].val = gt1;
				(currfunc->code)[gt1-1].val = currfunc->code.size();
				
			} else {
				(currfunc->code)[start].val = gt1;
			}
			
		} else if (t == T_WHILE){
			
			int start = currfunc->code.size();
			tokens->getNextToken();
			E();
			
			assert_token(TYPE_RES, T_DO);
			
			int gt = currfunc->code.size();
			currfunc->code.push_back( PolizInstruction(TIfNot) );
			
			tokens->getNextToken();			
			ST();
			
			currfunc->code.push_back( PolizInstruction(TGoto, start) );
			(currfunc->code)[gt].val = currfunc->code.size();
			
			
		} else if (t == T_BEGIN){			
			BL();
			
		} else if (t == T_RETURN){
			if (currfunc->return_type == VOID)
				error("Function can't return a value");
			tokens->getNextToken();
			E();
			currfunc->code.push_back( PolizInstruction(TReturn, currfunc->return_type) );
			
		} else if (t == T_WRITE){
			tokens->getNextToken();
			assert_token(TYPE_DELIM, T_LBRACK);
			
			tokens->getNextToken();			
			
			int params = 0;
			bool expected = false;
			for(;;){
				if (token()->type == TYPE_DELIM && token()->getLong()==T_RBRACK){
					if (expected)
						error("Wrong ',' before ')'");
					break;
				}
				
				expected = false;
				
				++params;
				if (token()->type==TYPE_LITSTR){
					PolizInstruction i = PolizInstruction(TStrLit, 0);
					i.str=token()->str;
					currfunc->code.push_back( i );
					tokens->getNextToken();
				} else
					E();
				
				if (token()->type == TYPE_DELIM){
					if (token()->getLong()==T_COMMA){
						expected = true;
						tokens->getNextToken();
					} else if (token()->getLong()!=T_RBRACK)
						error("Operands in 'write' statement must be separated by ','");
				} else 
					error("Operands in 'write' statement must be separated by ','");
				
			}			
			if (params == 0)
				error("'write' statetment can't be without arguments");
							
			currfunc->code.push_back( PolizInstruction(TWrite, params) );
			tokens->getNextToken();
			
		} else if (t == T_READ){
			tokens->getNextToken();
			if (token()->type != TYPE_ID)
				error("wrong 'read' statement. Expected ID after 'read'");
			
			std::string& id = token()->str; 
			if (!containsId(id))
				error("Undeclared identifier '" + id +"'");
			
			currfunc->code.push_back( makeVarPoliz(id) );
			currfunc->code.push_back( PolizInstruction(TRead) );
			tokens->getNextToken();
			
		} else if (t == T_EXIT ){
			tokens->getNextToken();
			E();
			currfunc->code.push_back( PolizInstruction(TExit) );	
					
		} else
			error("Wrong statement");
		
	} else if (token()->type == TYPE_ID){
		
		std::string id = token()->str;
		
		tokens->getNextToken();
		
		if (token()->type == TYPE_DELIM && token()->getLong() == T_LBRACK) {	
			// Function call
			
			if (!prog->functions.contains(id))
				error("Function '"+id+"' is not declared");
				
			tokens->getNextToken();
			
			int params = 0;
			bool expected = false;
			for(;;) {
				
				if ( token()->type == TYPE_DELIM && token()->getLong() == T_RBRACK){
					if (expected)
						error("Wrong ',' befor ')'"); 
					break;
				}
				expected =false;
				
				++params;
				E();												
				
				if (token()->type == TYPE_DELIM){
					if (token()->getLong()==T_COMMA){
						expected = true;
						tokens->getNextToken();
					} else if (token()->getLong()!=T_RBRACK)
						error("Arguments must be separated by ',' in function call");
				} else 
					error("Arguments must be separated by ',' in function call");				
				
			}			
			
			Function& f = prog->functions.get(id);
			if (params != f.args_count)
				error("Wrong number of arguments in function '" + f.name +"' call");
			
			currfunc->code.push_back( PolizInstruction(TFunction, prog->functions.getPos(id)) );			
			if (f.return_type != VOID)
				currfunc->code.push_back( PolizInstruction(TPOP) );
			tokens->getNextToken();
			
		} else if (token()->type == TYPE_OPER && token()->getLong() == T_ASS) {
			// Assignment
			
			if ( !containsId(id) ) 
				error("ID '"+id+"' is not declared");
							
			currfunc->code.push_back( makeVarPoliz(id) );			
			
			tokens->getNextToken();
			E();
			
			currfunc->code.push_back( PolizInstruction(TOperation, T_ASS) );
			
		} else 
			error("Wrong statement. After ID expected '(' or '='");
		
		
	} else 
		error("Wrong statement");
}


/* *
 * needs currfunc
 * */
void SyntaticParser::E()
{
	E1();
	while ( token()->type == TYPE_OPER  && token()->getLong()==T_OR) {
		tokens->getNextToken();
		E1();
		currfunc->code.push_back( PolizInstruction(TOperation, T_OR) );
	}
}


void SyntaticParser::E1()
{
	E2();
	while ( token()->type == TYPE_OPER && token()->getLong()==T_AND) {
		tokens->getNextToken();
		E2();
		currfunc->code.push_back( PolizInstruction(TOperation, T_AND) );
	}
}

void SyntaticParser::E2()
{
	E7();
	
	if (token()->type == TYPE_OPER && (token()->getLong() == T_EQ || 
										token()->getLong() == T_NEQ)){
		int tt = token()->getLong();
		tokens->getNextToken();
		E7();
		currfunc->code.push_back( PolizInstruction(TOperation, tt) );
	}		
				
}

void SyntaticParser::E3()
{
	E4();
		
	while ( token()->type == TYPE_OPER && (token()->getLong() == T_PLUS || 
										   token()->getLong() == T_MINUS ) ) {
		int tt = token()->getLong();
		tokens->getNextToken();
		E4();
		currfunc->code.push_back( PolizInstruction(TOperation, tt) );
	}

}

void SyntaticParser::E4()
{
	E5();
		
	while ( token()->type == TYPE_OPER && (token()->getLong() == T_MUL || 
										   token()->getLong() == T_DIV ||
										   token()->getLong() == T_MOD ) ) {
		int tt = token()->getLong();
		tokens->getNextToken();
		E5();
		currfunc->code.push_back( PolizInstruction(TOperation, tt) );
	}
}

void SyntaticParser::E5()
{
	E6();
	
	if (token()->type == TYPE_OPER && (token()->getLong() == T_DEG)){
		int tt = token()->getLong();
		tokens->getNextToken();
		E6();
		currfunc->code.push_back( PolizInstruction(TOperation, tt) );
	}
}

void SyntaticParser::E6()
{
	if (token()->type != TYPE_ID) {
		
		if (token()->type == TYPE_RES && token()->getLong() == T_WASERROR){
			currfunc->code.push_back( PolizInstruction(TWasError) );
			tokens->getNextToken();
			
		} else if (token()->type == TYPE_LIT){
			PolizInstruction i(TLiteral,INT);
			if (token()->isFloat)
				i.val = FLOAT;
			i.value = token()->value;
			currfunc->code.push_back(i);
			tokens->getNextToken();
			
		}else if (token()->type == TYPE_OPER){
			long op = token()->getLong();
			
			if (op == T_NOT){
			} else if (op == T_PLUS){
				op = T_PLUSUN;								
			} else if (op == T_MINUS){
				op = T_MINUSUN;
			} else
				error("Wrong operation in expression");
				
			tokens->getNextToken();
			E6();
			
			currfunc->code.push_back( PolizInstruction(TOperation, op) );			
			
		} else if (token()->type == TYPE_DELIM && token()->getLong() == T_LBRACK){
			tokens->getNextToken();
			E();
			assert_token(TYPE_DELIM, T_RBRACK);
			tokens->getNextToken();
			
		} else 
			error ("Wrong expression");
		
	} else { // ID
		
		assert_token(TYPE_ID, 0);
		
		std::string id = token()->str;
		int line = tokens->getLineNumber();
		 
		tokens->getNextToken();
		
		if (token()->type == TYPE_DELIM && token()->getLong() == T_LBRACK) {	
			// Function call						 
			
			if (!prog->functions.contains(id))
				error("Function '"+id+"' is not declared");
			
			Function& f = prog->functions.get(id);
			
			if (f.return_type == VOID)
				error("Function '" + f.name + "' doesn't return a value. You can't use it in expression");
			
			tokens->getNextToken();
			
			int params = 0;
			bool expected = false;
			for(;;) {
				
				if ( token()->type == TYPE_DELIM && token()->getLong() == T_RBRACK){
					if (expected)
						error("Wrong ',' befor ')'"); 
					break;
				}
				expected =false;
				
				++params;
				E();												
				
				if (token()->type == TYPE_DELIM){
					if (token()->getLong()==T_COMMA){
						expected = true;
						tokens->getNextToken();
					} else if (token()->getLong()!=T_RBRACK)
						error("Arguments must be separated by ',' in function call");
				} else 
					error("Arguments must be separated by ',' in function call");				
				
			}
			tokens->getNextToken();
			
			if (params != f.args_count)
				error("Wrong number of arguments in function '" + f.name +"' call");
			
			currfunc->code.push_back( PolizInstruction(TFunction, prog->functions.getPos(id)) );						
			
		}else {
			// ID
			if ( !containsId(id) )
				throw SyntacticParserException("Id '"+id+"' is not declared", line);				
							
			currfunc->code.push_back( makeVarPoliz(id) );						
			
		}
		
	} 
}

void SyntaticParser::E7()
{
	E3();
	if (token()->type == TYPE_OPER && (	token()->getLong() == T_GRT || 
										token()->getLong() == T_GRTEQ ||
										token()->getLong() == T_LSS ||
										token()->getLong() == T_LSSEQ ) ){
											
		int tt = token()->getLong();
		tokens->getNextToken();
		E3();
		currfunc->code.push_back( PolizInstruction(TOperation, tt) );
	}
}


}
Соседние файлы в папке MyLanguage