//
// 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 : Sun Jul 24 02:17:01 2016
// Update Count     : 90
// 

#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 Type::Qualifiers emptyQualifiers;				// no qualifiers on constants

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'; }

ConstantNode *makeConstantInteger( std::string & str ) {
	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 = str.length() - 1;						// last character of constant

	if ( str[0] == '0' ) {								// octal/hex constant ?
		dec = false;
		if ( last != 0 && checkX( str[1] ) ) {			// hex constant ?
			sscanf( (char *)str.c_str(), "%llx", &v );
			//printf( "%llx %llu\n", v, v );
		} else {										// octal constant
			sscanf( (char *)str.c_str(), "%llo", &v );
			//printf( "%llo %llu\n", v, v );
		} // if
	} else {											// decimal constant ?
		sscanf( (char *)str.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( str[last] ) ) {						// suffix 'u' ?
		Unsigned = true;
		if ( last > 0 && checkL( str[last - 1] ) ) {	// suffix 'l' ?
			size = 1;
			if ( last > 1 && checkL( str[last - 2] ) ) { // suffix 'll' ?
				size = 2;
			} // if
		} // if
	} else if ( checkL( str[ last ] ) ) {				// suffix 'l' ?
		size = 1;
		if ( last > 0 && checkL( str[last - 1] ) ) { // suffix 'll' ?
			size = 2;
			if ( last > 1 && checkU( str[last - 2] ) ) { // suffix 'u' ?
				Unsigned = true;
			} // if
		} else {
			if ( last > 0 && checkU( str[last - 1] ) ) { // suffix 'u' ?
				Unsigned = true;
			} // if
		} // if
	} // if

	return new ConstantNode( new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[Unsigned][size] ), str ), nullptr ) );
} // makeConstantInteger

ConstantNode *makeConstantFloat( std::string & str ) {
	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 = str.length() - 1;

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

	if ( checkF( str[last] ) ) {						// float ?
		size = 0;
	} else if ( checkD( str[last] ) ) {					// double ?
		size = 1;
	} else if ( checkL( str[last] ) ) {					// long double ?
		size = 2;
	} // if
	if ( ! complx && checkI( str[last - 1] ) ) {		// imaginary ?
		complx = true;
	} // if

	return new ConstantNode( new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[complx][size] ), str ), nullptr ) );
} // makeConstantFloat

ConstantNode *makeConstantChar( std::string & str ) {
	return new ConstantNode( new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::Char ), str ), nullptr ) );
} // makeConstantChar

ConstantNode *makeConstantStr( std::string & str ) {
	// 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 ) );
} // makeConstantStr


// 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: //
