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

📄 stdinterpreter.cpp

📁 Standard Grammar Toolkit
💻 CPP
字号:
/*=========================================================
StdInterpreter.cpp
Copyright (C) 2001, ClearJump, All Rights Reserved
=========================================================*/

#include "StdInterpreter.h"
#include <math.h>

//LOCAL DEFINITIONS
//=================
#define HEXMAXLEN (8)
#define DECMAXLEN (10)


//IMPLEMENTATION
//==============
StdInterpreter::StdInterpreter()
{
}

StdInterpreter::~StdInterpreter()
{
}

//'node' is of nid_String type
//this method appends the new string to 'str'
//it returns FALSE if there is an error
BOOL StdInterpreter::process_string( HPTNODE node, string& str )
{
	HPTNODE   child;
	SPtnInfo  info;
	CPERR     err;
	string    esc;

	str="";

	//enumerate children
	child = m_parser->GetFirstChild( node );
	for( ; child; child = m_parser->GetNextSibling(child) )
	{
		//the child node info
		err = m_parser->GetNodeInfo( child, info );
		if( err != CPERR_OK ) return error( child, err );

		//look for esc codes and identifiers
		//identifiers represent parts of the string 
		//between esc codes
		switch( info.nNodeType )
		{
		case CPT_NONTERMINAL:
			//correct strings should not contain any nonterminals
			//except esc codes
			if( info.nSymbolID != nid_EscCode )
				return error( child, InterpreterError::E_BADTREE );
			//get the esc code
			if( !process_esccode(child, esc) )
				return FALSE;
			//append the code
			str += esc;
			break;

		case CPT_IDENTIFIER:
			//append the string chunk
			str += info.pszIdentifier;
			break;

		default:
			return error( child, InterpreterError::E_BADTREE );
		}
	}

	return TRUE;
}

//nid_Integer
BOOL StdInterpreter::process_integer( HPTNODE node, UINT& num )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) return error( child, err );

	//must be nonterminal
	if( info.nNodeType != CPT_NONTERMINAL )
		return error( child, InterpreterError::E_BADTREE );

	switch( info.nSymbolID )
	{
	//hex integer
	case nid_HexInteger:
		return process_hexint( child, num );

	//decimal integer
	case nid_DecInteger:
		return process_decint( child, num );
	}

	return error( child, InterpreterError::E_BADTREE );
}

//nid_HexInteger
BOOL StdInterpreter::process_hexint( HPTNODE node, UINT& num )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) return error( child, err );

	//must be an identifier with the number
	if( info.nNodeType != CPT_IDENTIFIER || !info.pszIdentifier )
		return error( child, InterpreterError::E_BADTREE );

	if( strlen(info.pszIdentifier) > HEXMAXLEN ) //the number is too long
		//notify but don't stop
		error( child, InterpreterError::E_NUMBER_TOOLONG );

	CPCHAR *pdum;
	string tmp;
	tmp = "0x";  //hex number
	tmp += info.pszIdentifier;

	num = strtoul( tmp.data(), &pdum, 16 );

	return TRUE;
}

//nid_DecInteger
BOOL StdInterpreter::process_decint( HPTNODE node, UINT& num )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) return error( child, err );

	//must be an identifier with the number
	if( info.nNodeType != CPT_IDENTIFIER || !info.pszIdentifier )
		return error( child, InterpreterError::E_BADTREE );

	if( strlen(info.pszIdentifier) > DECMAXLEN )  //the number is too long
		//notify but don't stop
		error( child, InterpreterError::E_NUMBER_TOOLONG );

	CPCHAR *pdum;
	num = strtoul( info.pszIdentifier, &pdum, 10 );

	return TRUE;
}

//nid_SignedInteger
BOOL StdInterpreter::process_signed_integer( HPTNODE node, INT& num )
{
	HPTNODE    child;

	//get the number sign
	//-------------------

	BOOL minus;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//must be NumberSign symbol
	if( !process_number_sign( child, minus ) )
		return FALSE;

	//get the number
	//--------------

	//the next child
	child = m_parser->GetNextSibling( child );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//get the number
	//must be a decimal integer
	UINT tmp;
	if( !process_decint( child, tmp ) )
		return FALSE;

	if( tmp > INT_MAX )
		//notify but don't stop
		error( child, InterpreterError::E_NUMBER_TOOLONG );

	//finally set the sign
	if( minus ) num = (INT)tmp;
	else num = -((INT)tmp);

	return TRUE;
}

//nid_FloatNumber
BOOL StdInterpreter::process_float( HPTNODE node, double& num )
{
	return process_number( node, num );
}

//nid_Number
BOOL StdInterpreter::process_number( HPTNODE node, double& num )
{
	string numstr;

	//we reconstruct the string in order to use strtod()
	if( !reconstruct_number(node, numstr) )
		return FALSE;

	if( numstr.empty() ) 
		return error( node, InterpreterError::E_BADTREE );

	//convet the string
	CPCHAR *end;
	double x;
	x = strtod( numstr.data(), &end );
	if( x == HUGE_VAL ) //the number is too big
		return error( node, InterpreterError::E_NUMBER_TOOLONG );

	num = x;
	return TRUE;
}

	//nid_Symbol
BOOL StdInterpreter::process_symbol( HPTNODE node, CPCHAR& sym )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) return error( child, err );

	//must be a terminal
	if( info.nNodeType != CPT_TERMINAL )
		return error( child, InterpreterError::E_BADTREE );

	CPCSTR ps;
	ps = get_match( info );
	if( !ps ) return error( child, InterpreterError::E_BADTREE );
	sym = ps[0];

	return TRUE;
}

//nid_Identifer
BOOL StdInterpreter::process_identifier( HPTNODE node, CPCSTR *pid )
{
	*pid = get_child_identifier( node );
	if( !*pid ) return FALSE;
	return TRUE;
}

//an empty error handler
void StdInterpreter::error_notify( InterpreterError& err )
{
}

//process string esc codes
//nid_EscCode
BOOL StdInterpreter::process_esccode( HPTNODE node, string& code )
{
	HPTNODE    child;
	SPtnInfo   info;
	CPERR      err;
	UINT       num_code;
	CPCHAR     tmp[2]={0,0};

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) return error( child, err );

	//process the child
	switch( info.nNodeType )
	{
	//numeric code
	case CPT_NONTERMINAL:
		//numeric nonterminals only
		if( info.nSymbolID != nid_Integer )
			return error( child, InterpreterError::E_BADTREE );
		//process the numeric code
		if( !process_integer( child, num_code ) )
			return FALSE;
		//the number is too big?
		if( num_code > (CPCHAR)(-1) )
			//notify but don't stop
			error( child, InterpreterError::E_NUMBER_TOOLONG );
		//create the string
		tmp[0] = (CPCHAR)num_code;
		code = tmp;
		break;

	//get the code
	case CPT_TERMINAL:
		switch( info.nSymbolID )  //symbol id
		{
		case tid_esc_t:
			code = "\t";
			break;

		case tid_esc_n:
			code = "\n";
			break;

		case tid_esc_r:
			code = "\r";
			break;

		//use the grammar item data to get
		//the actual codes for these symbols
		//as it was defined by the grammar
		case tid_esc_open:
		case tid_str_close:
		case tid_str_open:
			{
				CPCSTR ps;
				ps = get_match( info );
				if( !ps ) return error( child, InterpreterError::E_BADTREE );
				code = ps;
			}
			break;

		default:
			return error( child, InterpreterError::E_BADTREE );
		}
		break;

	default:
		return error( child, InterpreterError::E_BADTREE );
	}
	return TRUE;
}

//nid_NumberSign
BOOL StdInterpreter::process_number_sign( HPTNODE node, BOOL& minus )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;

	//the sign is plus by default
	minus = FALSE;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child ) 
		//no children, the sign is plus by default
		return TRUE;

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) return error( child, err );

	//must be a terminal
	if( info.nNodeType != CPT_TERMINAL ) 
		return error( node, InterpreterError::E_BADTREE );

	//is it minus?
	if( info.nSymbolID == tid_minus )
		minus = TRUE;

	return TRUE;
}

CPCSTR StdInterpreter::get_child_identifier( HPTNODE node )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;

	//get the child node
	child = m_parser->GetFirstChild( node );
	if( !child )
	{
		error( node, InterpreterError::E_BADTREE );
		return NULL;
	}

	//get the child info
	err = m_parser->GetNodeInfo( child, info );
	if( err != CPERR_OK ) 
	{
		error( child, err );
		return NULL;
	}

	//must be an identifier
	if( info.nNodeType != CPT_IDENTIFIER || !info.pszIdentifier )
	{
		error( child, InterpreterError::E_BADTREE );
		return NULL;
	}

	return info.pszIdentifier;
}

//nid_FloatNumber & nid_Number
//we don't really check the grammar rules here,
//it should have already been done by the parser
BOOL StdInterpreter::reconstruct_number( HPTNODE node, string& numstr )
{
	CPERR      err;
	HPTNODE    child;
	SPtnInfo   info;
	BOOL       minus;

	//reconstruct the number string
	//---------------------------------------------------

	child = m_parser->GetFirstChild( node );
	if( !child ) return error( node, InterpreterError::E_BADTREE );

	for( ; child; child = m_parser->GetNextSibling( child ) )
	{
		//get the child info
		err = m_parser->GetNodeInfo( child, info );
		if( err != CPERR_OK ) return error( child, err );

		if( info.nNodeType == CPT_NONTERMINAL )
		{
			switch( info.nSymbolID )
			{
			case nid_DecInteger:
				if( !append_decint( child, numstr ) )
					return FALSE;
				break;

			case nid_ExpPoint:
				numstr += "e";
				break;

			case nid_NumberSign:
				if( !process_number_sign( child, minus ) )
					return FALSE;
				if( minus ) numstr += "-";
				break;

			case nid_FloatNumber:
				if( !reconstruct_number( child, numstr ) )
					return FALSE;
				break;

			case nid_Number:
				if( !reconstruct_number( child, numstr ) )
					return FALSE;
				break;
			}
		}
		//decimal point
		else if( info.nNodeType == CPT_TERMINAL && info.nSymbolID == tid_dec_point )
		{
			numstr += ".";
		}
		else
		{
			return error( child, InterpreterError::E_BADTREE );
		}
	}

	return TRUE;
}

//nid_DecInteger
BOOL StdInterpreter::append_decint( HPTNODE node, string& numstr )
{
	CPCSTR ps;
	ps = get_child_identifier( node );
	if( !ps ) return error( node, InterpreterError::E_BADTREE );
	numstr += ps;
	return TRUE;
}

	//get matching string for the terminal node
CPCSTR StdInterpreter::get_match( const SPtnInfo& info )
{
	CPERR      err;
	SGramItem  item;
	//get grammar item for this node
	err = m_parser->GramGetItemInfo( info.hGramItem, item );
	if( err != CPERR_OK ) return NULL;

	//the item must be a terminal
	if( item.nItemType != GIT_TERMINAL )
		return NULL;

	return item.Term.pszMatch;
}

⌨️ 快捷键说明

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