/*
 * Copyright (c) 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Flick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <mom/c/scml.hh>

scml_parser::scml_parser()
{
	this->ssp = 0;
}

scml_parser::~scml_parser()
{
}

void scml_parser::set_stream_pos(struct scml_stream_pos *the_ssp)
{
	this->ssp = the_ssp;
}

struct scml_stream_pos *scml_parser::get_stream_pos()
{
	return( this->ssp );
}

struct scml_token scml_parser::collapse(struct scml_token_stack *values,
					struct scml_token *oper)
{
	struct scml_token retval;
	
	retval.kind = SCML_ERROR;
	switch( oper->kind ) {
	case SCML_NT_COLON:
		if( (values->count() >= 2) &&
		    values->index(-1)->is_expr() &&
		    values->index(0)->is_expr() ) {
			retval.kind = SCML_NT_TAG;
			retval.value.children = new scml_token[2];
			retval.value.children[1] = *values->index(0);
			values->pop();
			retval.value.children[0] = *values->index(0);
			values->pop();
		}
		break;
	case SCML_TERM_RPAREN:
		retval.kind = SCML_NT_EXPR;
		retval.value.children = new scml_token[1];
		retval.value.children[0] = *values->index(0);
		values->pop();
		break;
	case SCML_TERM_RBRACE:
		if( (values->count() >= 2) &&
		    values->index(-1)->is_expr() &&
		    values->index(0)->is_expr() ) {
			retval.kind = SCML_NT_SEL;
			retval.value.children = new scml_token[2];
			retval.value.children[1] = *values->index(0);
			values->pop();
			retval.value.children[0] = *values->index(0);
			values->pop();
		}
		break;
	case SCML_TERM_RCURLY: {
		int lpc, args;
		
		for( args = 0; values->index(-args)->kind != SCML_TERM_LCURLY;
		     args++ );
		retval.kind = SCML_NT_INIT;
		retval.value.children = new scml_token[args + 1];
		retval.value.children[args].kind = SCML_NONE;
		for( lpc = 0; lpc < args; lpc++ ) {
			retval.value.children[args - lpc - 1] =
				*values->index(0);
			values->pop();
		}
		values->pop();
		break;
	}
	case SCML_TERM_GT: {
		int lpc, args;
		
		for( args = 0; values->index(-args)->kind != SCML_TERM_LT;
		     args++ );
		if( args ) {
			retval.kind = SCML_NT_COMMAND;
			retval.value.children = new scml_token[args + 1];
			retval.value.children[args].kind = SCML_NONE;
			for( lpc = 0; lpc < args; lpc++ ) {
				retval.value.children[args - lpc - 1] =
					*values->index(0);
				values->pop();
			}
			values->pop();
		}
		break;
	}
	case SCML_NT_SCOPE_RES:
		if( (values->count() >= 2) ) {
			oper->value.children = new scml_token[2];
			oper->value.children[1] = *values->index(0);
			values->pop();
			oper->value.children[0] = *values->index(0);
			values->pop();
			retval.kind = SCML_NT_NAME;
			retval.value.children = new scml_token;
			retval.value.children[0] = *oper;
		}
		break;
	case SCML_NT_ASSIGN:
		if( (values->count() >= 2) &&
		    (values->index(-1)->is_expr()) &&
		    values->index(0)->is_expr() ) {
			oper->kind = SCML_NT_SET;
			oper->value.children = new scml_token[2];
			oper->value.children[1] = *values->index(0);
			values->pop();
			oper->value.children[0] = *values->index(0);
			values->pop();
			retval.kind = SCML_NT_EXPR;
			retval.value.children = new scml_token;
			retval.value.children[0] = *oper;
		}
		break;
	case SCML_NT_NOT:
		if( (values->count() >= 1) &&
		    (values->index(0)->is_expr()) ) {
			oper->value.children = new scml_token[1];
			oper->value.children[0] = *values->index(0);
			values->pop();
			retval.kind = SCML_NT_EXPR;
			retval.value.children = new scml_token;
			retval.value.children[0] = *oper;
		}
		break;
	case SCML_NT_PLUS:
	case SCML_NT_MINUS:
	case SCML_NT_DIV:
	case SCML_NT_MOD:
	case SCML_NT_MULT:
	case SCML_NT_EQUAL:
	case SCML_NT_NOT_EQUAL:
	case SCML_NT_LT:
	case SCML_NT_GT:
	case SCML_NT_LE:
	case SCML_NT_GE:
	case SCML_NT_AND:
	case SCML_NT_LAND:
	case SCML_NT_OR:
	case SCML_NT_LOR:
	case SCML_NT_DOT:
		if( (values->count() >= 2) &&
		    values->index(0)->is_expr() &&
		    values->index(-1)->is_expr() ) {
			oper->value.children = new scml_token[2];
			oper->value.children[1] = *values->index(0);
			values->pop();
			oper->value.children[0] = *values->index(0);
			values->pop();
			retval.kind = SCML_NT_EXPR;
			retval.value.children = new scml_token;
			retval.value.children[0] = *oper;
		} else {
			scml_alert(this->ssp, SAF_ERROR|SAF_GENERAL,
				   "Bad args for %s (%d:%d:%d)",
				   scml_kind_map[oper->kind],
				   values->count(),
				   values->index(0)->is_expr(),
				   values->index(-1)->is_expr());
			printf("index(0) "); values->index(0)->print(); printf("\n");
			printf("index(-1) "); values->index(-1)->print(); printf("\n");
		}
		break;
	default:
		break;
	}
	values->push(retval);
	return( retval );
}

struct scml_token_sequence *scml_parser::parse()
{
	struct scml_token_stack values, operators;
	struct scml_token_sequence *retval = 0;
	struct scml_token curr, last;
	int lpc, done = 0, error = 0;
	
	last.kind = SCML_NONE;
	while( !done ) {
		curr = this->ssp->get_token();
		if( curr.kind == SCML_DONE ) {
			done = 1;
		} else if( curr.is_value() ) {
			while( last.is_value() &&
			       operators.count() &&
			       !operators.index(0)->is_container() ) {
				this->collapse(&values,
					       operators.index(0));
				operators.pop();
			}
			values.push(curr);
			last = curr;
		}
		else if( curr.is_operator() ) {
			if( (curr.kind == SCML_NT_DIV) && values.count() &&
			    (values.index(0)->kind == SCML_TERM_LT) ) {
				curr.kind = SCML_TERM_SLASH;
				values.push(curr);
			} else {
				if( operators.count() &&
				    !operators.index(0)->is_container() &&
				    (curr.get_prec() <=
				     operators.index(0)->get_prec()) ) {
					this->collapse(&values,
						       operators.index(0));
					operators.pop();
				}
				operators.push(curr);
			}
			last = curr;
		}
		else if( curr.is_container() ) {
			switch( curr.kind ) {
			case SCML_TERM_LT:
				values.push(curr);
				break;
			case SCML_TERM_GT:
				while( operators.count() ) {
					this->collapse(&values,
						       operators.index(0));
					operators.pop();
				}
				last = this->collapse(&values,
						      &curr);
				break;
			case SCML_TERM_LPAREN:
				operators.push(curr);
				break;
			case SCML_TERM_RPAREN:
				while( operators.count() &&
				       (operators.index(0)->kind !=
					SCML_TERM_LPAREN) ) {
					this->collapse(&values,
						       operators.index(0));
					operators.pop();
				}
				if( operators.count() ) {
					operators.pop();
					last = this->collapse(&values, &curr);
				} else {
					scml_alert(this->ssp,
						   SAF_ERROR|SAF_LEXICAL,
						   "Mismatched parentheses");
					error = 1;
					done = 1;
				}
				break;
			case SCML_TERM_LBRACE:
				if( operators.count() &&
				    !operators.index(0)->is_container() &&
				    (curr.get_prec() <=
				     operators.index(0)->get_prec()) ) {
					this->collapse(&values,
						       operators.index(0));
					operators.pop();
				}
				operators.push(curr);
				break;
			case SCML_TERM_RBRACE:
				while( operators.count() &&
				       (operators.index(0)->kind !=
					SCML_TERM_LBRACE) ) {
					this->collapse(&values,
						       operators.index(0));
					operators.pop();
				}
				if( operators.count() ) {
					operators.pop();
					last = this->collapse(&values, &curr);
				} else {
					scml_alert(this->ssp,
						   SAF_ERROR|SAF_LEXICAL,
						   "Mismatched braces");
					error = 1;
					done = 1;
				}
				break;
			case SCML_TERM_LCURLY:
				values.push(curr);
				operators.push(curr);
				break;
			case SCML_TERM_RCURLY:
				while( operators.count() &&
				       operators.index(0)->kind !=
				       SCML_TERM_LCURLY ) {
					this->collapse(&values,
						       operators.index(0));
					operators.pop();
				}
				if( operators.count() ) {
					operators.pop();
					last = this->collapse(&values, &curr);
				} else {
					scml_alert(this->ssp,
						   SAF_ERROR|SAF_LEXICAL,
						   "Mismatched braces");
					error = 1;
					done = 1;
				}
				break;
			default:
				break;
			}
		} else {
			switch( curr.kind ) {
			case SCML_IGNORE:
				break;
			case SCML_COL_POS:
				values.push(curr);
				break;
			case SCML_ROW_POS:
				values.push(curr);
				break;
			case SCML_ERROR:
				error = 1;
				scml_alert(this->ssp, SAF_ERROR|SAF_GENERAL,
					   "Invalid token");
				break;
			default:
				scml_alert(this->ssp, SAF_ERROR|SAF_GENERAL,
					   "Token not handled");
				curr.print(); printf("\n");
				error = 1;
				done = 1;
				break;
			}
		}
	}
	if( !error ) {
		retval = new scml_token_sequence();
		retval->set_value(new scml_token[values.count()]);
		retval->set_length(values.count());
		retval->set_stream_pos(this->ssp);
		for( lpc = 0; lpc < values.count(); lpc++ ) {
			retval->get_value()[values.count() - lpc - 1] =
				*values.index(-lpc);
		}
	} else {
		scml_alert(this->ssp, SAF_ERROR|SAF_GENERAL,
			   "Too many errors, bailing out");
	}
	return( retval );
}


syntax highlighted by Code2HTML, v. 0.9.1