/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1989-1999 Microsoft Corporation Module Name: exprpr.cxx Abstract: expression evaluator print routines implementation. Notes: History: VibhasC Aug-05-1993 Created ----------------------------------------------------------------------------*/ #pragma warning ( disable : 4514 ) /**************************************************************************** * include files ***************************************************************************/ #include "nulldefs.h" extern "C" { #include #include } #include "expr.hxx" #include "nodeskl.hxx" /**************************************************************************** * extern definitions ***************************************************************************/ extern char * OperatorToString( OPERATOR Op ); /***************************************************************************/ void expr_node::PrintWithPrefix( ISTREAM * pStream, char * pPrefix ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: This routine prints an expression adding a prefix to each of the varaibles within the expression. Arguments: pStream - A pointer to the stream to output to. pPrefix - the prefix to be prepended to each variable Return Value: Notes: ----------------------------------------------------------------------------*/ { ITERATOR VarList; expr_variable * pVarNode = 0; short VarCount = MakeListOfVars( VarList ); if ( VarCount ) { VarList.Init(); while ( ITERATOR_GETNEXT( VarList, pVarNode ) ) pVarNode->SetPrefix( pPrefix ); } Print( pStream ); if ( VarCount ) { VarList.Init(); while ( ITERATOR_GETNEXT( VarList, pVarNode ) ) pVarNode->SetPrefix( NULL ); } } /* // table of precedences ( lower number => lower precedence ) 200 [] () . -> ()++ ()-- 190 ++() --() sizeof() & *(deref) +() -() ~() !() 180 (cast) 170 * / % 160 + - 150 << >> 140 < > <= >= 130 == != 120 & (bitwise) 110 ^ 100 | 90 && 80 || 70 ?: 60 = *= /= %= += -= <<= >>= &= |= ^= 50 , (seqential eval) 0 all other operators (should be none) */ const short Prec[] = { 0 // OP_ILLEGAL = OP_START // OP_UNARY_START // OP_UNARY_ARITHMETIC_START = OP_UNARY_START ,190 // OP_UNARY_PLUS = OP_UNARY_ARITHMETIC_START ,190 // OP_UNARY_MINUS // OP_UNARY_ARITHMETIC_END // OP_UNARY_LOGICAL_START = OP_UNARY_ARITHMETIC_END ,190 // OP_UNARY_NOT = OP_UNARY_LOGICAL_START ,190 // OP_UNARY_COMPLEMENT // OP_UNARY_LOGICAL_END ,190 // OP_UNARY_INDIRECTION = OP_UNARY_LOGICAL_END ,180 // OP_UNARY_CAST ,190 // OP_UNARY_AND ,190 // OP_UNARY_SIZEOF ,190 // OP_UNARY_ALIGNOF ,190 // OP_PRE_INCR ,190 // OP_PRE_DECR ,200 // OP_POST_INCR ,200 // OP_POST_DECR // OP_UNARY_END // OP_BINARY_START = OP_UNARY_END // OP_BINARY_ARITHMETIC_START = OP_BINARY_START ,160 // OP_PLUS = OP_BINARY_ARITHMETIC_START ,160 // OP_MINUS ,170 // OP_STAR ,170 // OP_SLASH ,170 // OP_MOD // OP_BINARY_ARITHMETIC_END // OP_BINARY_SHIFT_START = OP_BINARY_ARITHMETIC_END ,150 // OP_LEFT_SHIFT = OP_BINARY_SHIFT_START ,150 // OP_RIGHT_SHIFT // OP_BINARY_SHIFT_END // OP_BINARY_RELATIONAL_START = OP_BINARY_SHIFT_END ,140 // OP_LESS = OP_BINARY_RELATIONAL_START ,140 // OP_LESS_EQUAL ,140 // OP_GREATER_EQUAL ,140 // OP_GREATER ,130 // OP_EQUAL ,130 // OP_NOT_EQUAL // OP_BINARY_RELATIONAL_END // OP_BINARY_BITWISE_START = OP_BINARY_RELATIONAL_END ,120 // OP_AND = OP_BINARY_BITWISE_START ,100 // OP_OR ,110 // OP_XOR // OP_BINARY_BITWISE_END // OP_BINARY_LOGICAL_START = OP_BINARY_BITWISE_END ,90 // OP_LOGICAL_AND = OP_BINARY_LOGICAL_START ,80 // OP_LOGICAL_OR // OP_BINARY_LOGICAL_END // OP_BINARY_TERNARY_START = OP_BINARY_LOGICAL_END ,70 // OP_QM = OP_BINARY_TERNARY_START ,70 // OP_COLON // OP_BINARY_TERNARY_END // OP_BINARY_END = OP_BINARY_TERNARY_END ,0 // OP_INTERNAL_START = OP_BINARY_END ,200 // OP_FUNCTION ,0 // OP_PARAM ,200 // OP_POINTSTO ,200 // OP_DOT ,200 // OP_INDEX ,50 // OP_COMMA ,0 // OP_STMT ,60 // OP_ASSIGN ,0 // OP_END }; /* // table of associativity ( -1 => L to R, 1 => R to L ) -1 [] () . -> ()++ ()-- 1 ++() --() sizeof() & *(deref) +() -() ~() !() 1 (cast) -1 * / % -1 + - -1 << >> -1 < > <= >= -1 == != -1 & (bitwise) -1 ^ -1 | -1 && -1 || 1 ?: 1 = *= /= %= += -= <<= >>= &= |= ^= -1 , (seqential eval) 0 all other operators (should be none) */ const short AssocTbl[] = { 0 // OP_ILLEGAL = OP_START // OP_UNARY_START // OP_UNARY_ARITHMETIC_START = OP_UNARY_START ,-1 // OP_UNARY_PLUS = OP_UNARY_ARITHMETIC_START ,-1 // OP_UNARY_MINUS // OP_UNARY_ARITHMETIC_END // OP_UNARY_LOGICAL_START = OP_UNARY_ARITHMETIC_END ,1 // OP_UNARY_NOT = OP_UNARY_LOGICAL_START ,1 // OP_UNARY_COMPLEMENT // OP_UNARY_LOGICAL_END ,1 // OP_UNARY_INDIRECTION = OP_UNARY_LOGICAL_END ,1 // OP_UNARY_CAST ,1 // OP_UNARY_AND ,1 // OP_UNARY_SIZEOF ,1 // OP_UNARY_ALIGNOF ,1 // OP_PRE_INCR ,1 // OP_PRE_DECR ,-1 // OP_POST_INCR ,-1 // OP_POST_DECR // OP_UNARY_END // OP_BINARY_START = OP_UNARY_END // OP_BINARY_ARITHMETIC_START = OP_BINARY_START ,-1 // OP_PLUS = OP_BINARY_ARITHMETIC_START ,-1 // OP_MINUS ,-1 // OP_STAR ,-1 // OP_SLASH ,-1 // OP_MOD // OP_BINARY_ARITHMETIC_END // OP_BINARY_SHIFT_START = OP_BINARY_ARITHMETIC_END ,-1 // OP_LEFT_SHIFT = OP_BINARY_SHIFT_START ,-1 // OP_RIGHT_SHIFT // OP_BINARY_SHIFT_END // OP_BINARY_RELATIONAL_START = OP_BINARY_SHIFT_END ,-1 // OP_LESS = OP_BINARY_RELATIONAL_START ,-1 // OP_LESS_EQUAL ,-1 // OP_GREATER_EQUAL ,-1 // OP_GREATER ,-1 // OP_EQUAL ,-1 // OP_NOT_EQUAL // OP_BINARY_RELATIONAL_END // OP_BINARY_BITWISE_START = OP_BINARY_RELATIONAL_END ,-1 // OP_AND = OP_BINARY_BITWISE_START ,-1 // OP_OR ,-1 // OP_XOR // OP_BINARY_BITWISE_END // OP_BINARY_LOGICAL_START = OP_BINARY_BITWISE_END ,-1 // OP_LOGICAL_AND = OP_BINARY_LOGICAL_START ,-1 // OP_LOGICAL_OR // OP_BINARY_LOGICAL_END // OP_BINARY_TERNARY_START = OP_BINARY_LOGICAL_END ,1 // OP_QM = OP_BINARY_TERNARY_START ,1 // OP_COLON // OP_BINARY_TERNARY_END // OP_BINARY_END = OP_BINARY_TERNARY_END ,0 // OP_INTERNAL_START = OP_BINARY_END ,0 // OP_FUNCTION ,0 // OP_PARAM ,-1 // OP_POINTSTO ,-1 // OP_DOT ,-1 // OP_INDEX ,-1 // OP_COMMA ,0 // OP_STMT ,1 // OP_ASSIGN ,0 // OP_END }; void expr_operator::PrintSubExpr( expr_node * pExpr, ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Print a subexpression, optionally adding parens. Arguments: pExpr - the expression to print pStream - A pointer to the stream to output to. Return Value: Notes: ----------------------------------------------------------------------------*/ { short PrecMe = Prec[ GetOperator() ]; short PrecChild; BOOL fAddParens = FALSE; if ( pExpr->IsOperator() ) { PrecChild = Prec[ pExpr->GetOperator() ]; // account for associativity if ( pExpr != GetLeft() ) PrecChild = short( PrecChild + AssocTbl[ pExpr->GetOperator() ] ); fAddParens = PrecChild < PrecMe; } if ( fAddParens ) pStream->Write('('); pExpr->Print( pStream ); if ( fAddParens ) pStream->Write(')'); } void expr_variable::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Print a variable name expression. Arguments: pStream - A pointer to the stream to output to. Return Value: Notes: ----------------------------------------------------------------------------*/ { if ( GetPrefix() ) pStream->Write( GetPrefix() ); pStream->Write( GetName() ); } char * ConstFormats[] = { "\"%s\"", // string "L\"%Ls\"", // wstring "0x%x", // char "L'%Lc'", // wchar "%d", // numeric "%uU", // numeric unsigned "%ldL", // numeric long "%luUL", // numeric unsigned long "%#x", // hex "%#xU", // hex unsigned "%#lxL", // hex long "%#lxUL", // hex unsigned long "%#o", // octal "%#oU", // octal unsigned "%#loL", // octal long "%#loUL", // octal unsigned long "%s", // BOOL ( not used ) "%g", // float "%lg", // double // RKK64 // value types for int64 }; void expr_constant::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a constant expression to the stream. Arguments: pStream - A pointer to the stream. Return Value: Notes: ----------------------------------------------------------------------------*/ { char Array[ 256 ]; Array[0] = 0; if (Format == VALUE_TYPE_BOOL) { sprintf( Array, "%s", (Value.L) ? "TRUE" : "FALSE" ); } else if ( Format == VALUE_TYPE_FLOAT ) { sprintf( Array, ConstFormats[ Format] , Value.F ); } else if ( Format == VALUE_TYPE_DOUBLE ) { sprintf( Array, ConstFormats[ Format] , Value.D ); } else if ( Format == VALUE_TYPE_CHAR ) { if ( Value.C ) { Array[0] = '0'; Array[1] = 'x'; char ch = ( char ) ( ( Value.C >> 4 ) & 0xF ); Array[2] = ( char ) ( ( ch >= 0 && ch <= 9 ) ? ch + '0' : ch + 'A' - 0xA ); ch = ( char ) ( Value.C & 0xF ); Array[3] = ( char ) ( ( ch >= 0 && ch <= 9 ) ? ch + '0' : ch + 'A' - 0xA ); Array[4] = 0; } else { Array[0] = '0'; Array[1] = 0; } } else if ( Format == VALUE_TYPE_STRING ) { if (Value.pC) { pStream->Write( "\"" ); pStream->Write( ( char* ) Value.pC ); pStream->Write( "\"" ); } else { pStream->Write( "0" ); } } else if ( Format == VALUE_TYPE_WSTRING ) { if (Value.pWC) { pStream->Write( "L\"" ); pStream->Write( ( char* ) Value.pWC ); pStream->Write( "\"" ); } else { pStream->Write( "0" ); } } else { sprintf( Array, ConstFormats[ Format] , Value.I64 ); } pStream->Write( (char *)Array ); } void expr_op_unary::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a unary expression to the stream. Arguments: pStream - A pointer to the stream. Return Value: Notes: ----------------------------------------------------------------------------*/ { OPERATOR Op = GetOperator(); char ch; switch( Op ) { case OP_UNARY_PLUS: ch = '+'; break; case OP_UNARY_MINUS: ch = '-'; break; case OP_UNARY_NOT: ch = '!'; break; case OP_UNARY_COMPLEMENT: ch = '~'; break; case OP_UNARY_INDIRECTION: ch = '*'; break; case OP_UNARY_AND: ch = '&'; break; default: ch = 'X'; break; } pStream->Write( ch ); PrintSubExpr( GetLeft(), pStream ); } void expr_cast::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a cast expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { if ( GetEmitModifiers() == true ) { GetType()->PrintType( (PRT_CAST), pStream, (node_skl *)0 ); } else { GetType()->PrintType( (PRT_CAST) | PRT_SUPPRESS_MODIFIERS, pStream, (node_skl *)0 ); } PrintSubExpr( GetLeft(), pStream ); } void expr_sizeof::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a sizeof expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { pStream->Write( "sizeof" ); pType->PrintType( (PRT_CAST | PRT_ARRAY_SIZE_ONE), pStream, (node_skl *)0 ); } void expr_alignof::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a sizeof expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { pStream->Write( "__alignof" ); pType->PrintType( (PRT_CAST | PRT_ARRAY_SIZE_ONE), pStream, (node_skl *)0 ); } void expr_pre_incr::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a pre-incr expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { pStream->Write("++"); PrintSubExpr( GetLeft(), pStream ); } void expr_pre_decr::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a pre-decrement expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { pStream->Write("--"); PrintSubExpr( GetLeft(), pStream ); } void expr_post_incr::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a post-increment expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { PrintSubExpr( GetLeft(), pStream ); pStream->Write("++"); } void expr_post_decr::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a post-decrement expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { PrintSubExpr( GetLeft(), pStream ); pStream->Write("--"); } void expr_op_binary::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a binary arithmetic expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { PrintSubExpr( GetLeft(), pStream ); pStream->Write( OperatorToString( GetOperator() ) ); PrintSubExpr( GetRight(), pStream ); } void expr_op_binary::PrintCall( ISTREAM * pStream, short LeftMargin, BOOL fInProc ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression as part of a procedure call. Arguments: pStream - A pointer to the stream. LeftMargin - The start margin for the procedure call. fInProc - Is it in a proc context already ? Return Value: None. Notes: The left margin is 0 if the call is the only thing on the line. If the call is in an assignment, the start of param indent must take that into account. ----------------------------------------------------------------------------*/ { expr_node * pN; if ( ( pN = GetLeft() ) != 0 ) pN->PrintCall( pStream, LeftMargin, fInProc ); pStream->Write( OperatorToString( GetOperator() ) ); if ( ( pN = GetRight() ) != 0 ) pN->PrintCall( pStream, LeftMargin, fInProc ); } void expr_assign::PrintCall( ISTREAM * pStream, short LeftMargin, BOOL fInProc ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression as part of a procedure call. Arguments: pStream - A pointer to the stream. LeftMargin - The start margin for the procedure call. fInProc - Is it in a proc context already ? Return Value: None. Notes: The left margin is 0 if the call is the only thing on the line. If the call is in an assignment, the start of param indent must take that into account. ----------------------------------------------------------------------------*/ { expr_node * pN; if ( ( pN = GetLeft() ) != 0 ) pN->PrintCall( pStream, LeftMargin, fInProc ); pStream->Write( " = " ); if ( ( pN = GetRight() ) != 0 ) pN->PrintCall( pStream, LeftMargin, fInProc ); } void expr_index::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression for the array index operator. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: ----------------------------------------------------------------------------*/ { PrintSubExpr( GetLeft(), pStream ); pStream->Write( '[' ); GetRight()->Print( pStream ); pStream->Write( ']' ); } void expr_index::PrintCall( ISTREAM * pStream, short LeftMargin, BOOL fInProc ) { GetLeft()->PrintCall( pStream, LeftMargin, fInProc ); pStream->Write( '[' ); GetRight()->PrintCall( pStream, LeftMargin, fInProc ); pStream->Write( ']' ); } void expr_proc_call::PrintCall( ISTREAM * pStream, short LeftMargin, BOOL fInProc ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression for a procedure call. Arguments: pStream - A pointer to the stream. LeftMargin - The start margin for the procedure call. fInProc - Is it in a proc context already ? Return Value: None. Notes: The left margin is 0 if the call is the only thing on the line. If the call is in an assignment, the start of param indent must take that into account. ----------------------------------------------------------------------------*/ { PNAME pName = GetName(); unsigned short CurPref = pStream->GetPreferredIndent(); unsigned short CurIndent= pStream->GetIndent(); // // Print fancy only if more than 2 params. // if( GetNoOfParams() < 3 ) { Print( pStream ); if( !fInProc ) pStream->Write(';'); return; } pStream->Write( GetName() ); pStream->Write( '(' ); pStream->SetPreferredIndent( short( LeftMargin + CurPref + strlen( pName ) - CurIndent ) ); pStream->IndentInc(); pStream->NewLine(); if( GetFirstParam()) { GetFirstParam()->PrintCall( pStream, LeftMargin, TRUE // now in proc context ); } pStream->Write( ')' ); if( !fInProc ) pStream->Write( ';' ); pStream->IndentDec(); pStream->SetPreferredIndent( CurPref ); } void expr_proc_call::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression for a procedure call. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: ----------------------------------------------------------------------------*/ { pStream->Write( GetName() ); pStream->Write( '(' ); if( GetFirstParam()) GetFirstParam()->Print( pStream ); pStream->Write( ')' ); } void expr_param::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression for a parameter. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: ----------------------------------------------------------------------------*/ { expr_node * pNextParam; GetLeft()->Print( pStream ); if ( ( pNextParam = GetNextParam() ) != 0 ) { pStream->Write( ',' ); // pStream->NewLine(); pNextParam->Print( pStream ); } } void expr_param::PrintCall( ISTREAM * pStream, short LeftMargin, BOOL fInProc ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit expression as part of a procedure call. Arguments: pStream - A pointer to the stream. LeftMargin - The start margin for the procedure call. fInProc - Is it in a proc context already ? pStream - A pointer to the stream. Return Value: None. Notes: ----------------------------------------------------------------------------*/ { expr_node * pNextParam; GetLeft()->PrintCall( pStream, LeftMargin, fInProc ); if ( ( pNextParam = GetNextParam() ) != 0 ) { pStream->Write( ',' ); pStream->NewLine(); pNextParam->PrintCall( pStream, LeftMargin, fInProc ); } } void expr_ternary::Print( ISTREAM * pStream ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Emit a ternary expression. Arguments: pStream - A pointer to the stream. Return Value: None. Notes: Not implemented for now. ----------------------------------------------------------------------------*/ { PrintSubExpr( GetRelational(), pStream ); pStream->Write( " ? " ); PrintSubExpr( GetLeft(), pStream ); pStream->Write( " : " ); PrintSubExpr( GetRight(), pStream ); } /**************************************************************************** utilities ****************************************************************************/ char * OperatorToString( OPERATOR Op ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Translate the operator to its string. Arguments: Op - The operator value. Return Value: Notes: ----------------------------------------------------------------------------*/ { char *p; switch( Op ) { case OP_PLUS: p = " + "; break; case OP_MINUS: p = " - "; break; case OP_STAR: p = " * "; break; case OP_SLASH: p = " / "; break; case OP_MOD: p = " % "; break; case OP_LEFT_SHIFT: p = " << "; break; case OP_RIGHT_SHIFT: p = " >> "; break; case OP_LESS: p = " < "; break; case OP_LESS_EQUAL: p = " <= "; break; case OP_GREATER_EQUAL: p = " >= "; break; case OP_GREATER: p = " > "; break; case OP_EQUAL: p = " == "; break; case OP_NOT_EQUAL: p = " != "; break; case OP_AND: p = " & "; break; case OP_OR: p = " | "; break; case OP_XOR: p = " ^ "; break; case OP_LOGICAL_AND: p = " && "; break; case OP_LOGICAL_OR: p = " || "; break; case OP_QM: p = " ? "; break; case OP_COLON: p = " : "; break; case OP_ASSIGN: p = " = "; break; case OP_DOT: p = " . "; break; case OP_POINTSTO: p = " -> "; break; case OP_COMMA: p = " , "; break; case OP_UNARY_NOT: p = " ! "; break; default: p = " X "; break; } return p; }