//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// ParseNode.cc -- 
//
// Author           : Rodolfo G. Esteves
// Created On       : Sat May 16 13:26:29 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Fri Jul 15 18:49:25 2016
// Update Count     : 62
// 

#include <climits>
#include "ParseNode.h"
using namespace std;

// Difficult to separate extra parts of constants during lexing because actions are not allow in the middle of patterns:
//
//		prefix action constant action suffix
//
// Alternatively, breaking a pattern using BEGIN does not work if the following pattern can be empty:
//
//		constant BEGIN CONT ...
//		<CONT>(...)? BEGIN 0 ... // possible empty suffix
//
// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
// type.

static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
static inline bool checkF( char c ) { return c == 'f' || c == 'F'; }
static inline bool checkD( char c ) { return c == 'd' || c == 'D'; }
static inline bool checkI( char c ) { return c == 'i' || c == 'I'; }
static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }

BasicType::Kind literalType( ConstantNode::Type type, string &value ) {
	BasicType::Kind btype;

	// lexing divides constants into 4 kinds
	switch ( type ) {
	  case ConstantNode::Integer:
		{
			static const BasicType::Kind kind[2][3] = {
				{ BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt },
				{ BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt },
			};
			bool dec = true, Unsigned = false;			// decimal, unsigned constant
			int size;									// 0 => int, 1 => long, 2 => long long
			unsigned long long v;						// converted integral value
			size_t last = value.length() - 1;			// last character of constant

			if ( value[0] == '0' ) {					// octal/hex constant ?
				dec = false;
				if ( last != 0 && checkX( value[1] ) ) { // hex constant ?
					sscanf( (char *)value.c_str(), "%llx", &v );
					//printf( "%llx %llu\n", v, v );
				} else {								// octal constant
					sscanf( (char *)value.c_str(), "%llo", &v );
					//printf( "%llo %llu\n", v, v );
				} // if
			} else {									// decimal constant ?
				sscanf( (char *)value.c_str(), "%llu", &v );
				//printf( "%llu %llu\n", v, v );
			} // if

			if ( v <= INT_MAX ) {						// signed int
				size = 0;
			} else if ( v <= UINT_MAX && ! dec ) {		// unsigned int
				size = 0;
				Unsigned = true;						// unsigned
			} else if ( v <= LONG_MAX ) {				// signed long int
				size = 1;
			} else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int
				size = 1;
				Unsigned = true;						// unsigned long int
			} else if ( v <= LLONG_MAX ) {				// signed long long int
				size = 2;
			} else {									// unsigned long long int
				size = 2;
				Unsigned = true;						// unsigned long long int
			} // if

			if ( checkU( value[last] ) ) {				// suffix 'u' ?
				Unsigned = true;
				if ( last > 0 && checkL( value[ last - 1 ] ) ) { // suffix 'l' ?
					size = 1;
					if ( last > 1 && checkL( value[ last - 2 ] ) ) { // suffix 'll' ?
						size = 2;
					} // if
				} // if
			} else if ( checkL( value[ last ] ) ) {		// suffix 'l' ?
				size = 1;
				if ( last > 0 && checkL( value[ last - 1 ] ) ) { // suffix 'll' ?
					size = 2;
					if ( last > 1 && checkU( value[ last - 2 ] ) ) { // suffix 'u' ?
						Unsigned = true;
					} // if
				} else {
					if ( last > 0 && checkU( value[ last - 1 ] ) ) { // suffix 'u' ?
						Unsigned = true;
					} // if
				} // if
			} // if
			btype = kind[Unsigned][size];				// lookup constant type
			break;
		}
	  case ConstantNode::Float:
		{
			//long double v;
			static const BasicType::Kind kind[2][3] = {
				{ BasicType::Float, BasicType::Double, BasicType::LongDouble },
				{ BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex },
			};
			bool complx = false;						// real, complex
			int size = 1;								// 0 => float, 1 => double (default), 2 => long double
			// floating-point constant has minimum of 2 characters: 1. or .1
			size_t last = value.length() - 1;

			if ( checkI( value[last] ) ) {				// imaginary ?
				complx = true;
				last -= 1;								// backup one character
			} // if

			//sscanf( (char *)value.c_str(), "%Lf", &v );
			//printf( "%s %24.22Lf %Lf\n", value.c_str(), v, v );

			if ( checkF( value[last] ) ) {				// float ?
				size = 0;
			} else if ( checkD( value[last] ) ) {		// double ?
				size = 1;
			} else if ( checkL( value[last] ) ) {		// long double ?
				size = 2;
			} // if
			if ( ! complx && checkI( value[last - 1] ) ) { // imaginary ?
				complx = true;
			} // if
			btype = kind[complx][size];					// lookup constant type
			break;
		}
	  case ConstantNode::Character:
		btype = BasicType::Char;						// default
		if ( string( "LUu" ).find( value[0] ) != string::npos ) {
			// ???
		} // if
		break;
	  case ConstantNode::String:
		assert( false );
		// array of char
		if ( string( "LUu" ).find( value[0] ) != string::npos ) {
			if ( value[0] == 'u' && value[1] == '8' ) {
				// ???
			} else {
				// ???
			} // if
		} // if
		break;
	} // switch
	return btype;
} // literalType


ConstantNode *makeConstant( ConstantNode::Type type, std::string *str ) {
	::Type::Qualifiers emptyQualifiers;					// no qualifiers on constants
	return new ConstantNode( new ConstantExpr( Constant( new BasicType( emptyQualifiers, literalType( type, *str ) ), *str ), nullptr ) );
}

ConstantNode *makeConstantStr( ConstantNode::Type type, std::string *str ) {
	::Type::Qualifiers emptyQualifiers;					// no qualifiers on constants
	// string should probably be a primitive type
	ArrayType *at = new ArrayType( emptyQualifiers, new BasicType( emptyQualifiers, BasicType::Char ),
								   new ConstantExpr(
									   Constant( new BasicType( emptyQualifiers, BasicType::UnsignedInt ),
												 toString( str->size()+1-2 ) ) ),  // +1 for '\0' and -2 for '"'
								   false, false );
	return new ConstantNode( new ConstantExpr( Constant( at, *str ), nullptr ) );
}


// Builder
int ParseNode::indent_by = 4;

ParseNode::ParseNode() : next( 0 ) {};
ParseNode::ParseNode( const string *name ) : name( *name ), next( 0 ) { delete name; }
ParseNode::ParseNode( const string &name ) : name( name ), next( 0 ) { }

ParseNode::~ParseNode() {
	delete next;
};

ParseNode *ParseNode::get_last() {
	ParseNode *current = this;

	while ( current->get_link() != 0 )
	current = current->get_link();

	return current;
}

ParseNode *ParseNode::set_link( ParseNode *next_ ) {
	if ( next_ != 0 ) get_last()->next = next_;
	return this;
}

void ParseNode::print( std::ostream &os, int indent ) const {}


void ParseNode::printList( std::ostream &os, int indent ) const {
	print( os, indent );

	if ( next ) {
		next->printList( os, indent );
	} // if
}

ParseNode &ParseNode::operator,( ParseNode &p ) {
	set_link( &p );

	return *this;
}

ParseNode *mkList( ParseNode &pn ) {
	// it just relies on `operator,' to take care of the "arguments" and provides a nice interface to an awful-looking
	// address-of, rendering, for example (StatementNode *)(&(*$5 + *$7)) into (StatementNode *)mkList(($5, $7))
	// (although "nice" is probably not the word)
	return &pn;
}

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
