| /* | |
| * File expr.c - expression handling for Wine internal debugger. | |
| * | |
| * Copyright (C) 1997, Eric Youngdale. | |
| * | |
| */ | |
| #include "config.h" | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "winbase.h" | |
| #include "wine/winbase16.h" | |
| #include "debugger.h" | |
| #include "expr.h" | |
| #include <stdarg.h> | |
| struct expr | |
| { | |
| unsigned int perm; | |
| unsigned int type:31; | |
| union | |
| { | |
| struct | |
| { | |
| int value; | |
| } constant; | |
| struct | |
| { | |
| const char * str; | |
| } string; | |
| struct | |
| { | |
| unsigned int value; | |
| } u_const; | |
| struct | |
| { | |
| const char * name; | |
| } symbol; | |
| struct | |
| { | |
| const char * name; | |
| } intvar; | |
| struct | |
| { | |
| int unop_type; | |
| struct expr * exp1; | |
| int result; | |
| } unop; | |
| struct | |
| { | |
| int binop_type; | |
| int result; | |
| struct expr * exp1; | |
| struct expr * exp2; | |
| } binop; | |
| struct | |
| { | |
| struct datatype * cast; | |
| struct expr * expr; | |
| } cast; | |
| struct | |
| { | |
| struct expr * exp1; | |
| const char * element_name; | |
| int result; | |
| } structure; | |
| struct | |
| { | |
| struct expr * base; | |
| struct expr * index; | |
| } array; | |
| struct | |
| { | |
| const char * funcname; | |
| int nargs; | |
| int result; | |
| struct expr * arg[5]; | |
| } call; | |
| } un; | |
| }; | |
| #define EXPR_TYPE_CONST 0 | |
| #define EXPR_TYPE_US_CONST 1 | |
| #define EXPR_TYPE_SYMBOL 2 | |
| #define EXPR_TYPE_INTVAR 3 | |
| #define EXPR_TYPE_BINOP 4 | |
| #define EXPR_TYPE_UNOP 5 | |
| #define EXPR_TYPE_STRUCT 6 | |
| #define EXPR_TYPE_PSTRUCT 7 | |
| #define EXPR_TYPE_ARRAY 8 | |
| #define EXPR_TYPE_CALL 9 | |
| #define EXPR_TYPE_STRING 10 | |
| #define EXPR_TYPE_CAST 11 | |
| static char expr_list[4096]; | |
| static unsigned int next_expr_free = 0; | |
| /* | |
| * This is how we turn an expression address into the actual value. | |
| * This works well in the 32 bit domain - not sure at all about the | |
| * 16 bit world. | |
| */ | |
| #define VAL(_exp) DEBUG_GetExprValue(&_exp, NULL) | |
| static | |
| struct expr * | |
| DEBUG_GetFreeExpr(void) | |
| { | |
| struct expr * rtn; | |
| rtn = (struct expr *) &expr_list[next_expr_free]; | |
| next_expr_free += sizeof(struct expr); | |
| assert(next_expr_free < sizeof(expr_list)); | |
| return rtn; | |
| } | |
| void | |
| DEBUG_FreeExprMem(void) | |
| { | |
| next_expr_free = 0; | |
| } | |
| struct expr * | |
| DEBUG_TypeCastExpr(struct datatype * dt, struct expr * exp) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_CAST; | |
| ex->un.cast.cast = dt; | |
| ex->un.cast.expr = exp; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_IntVarExpr(const char* name) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_INTVAR; | |
| ex->un.intvar.name = name; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_SymbolExpr(const char * name) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_SYMBOL; | |
| ex->un.symbol.name = name; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_ConstExpr(int value) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_CONST; | |
| ex->un.constant.value = value; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_StringExpr(const char * str) | |
| { | |
| struct expr * ex; | |
| char * pnt; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_STRING; | |
| ex->un.string.str = str+1; | |
| pnt = strrchr(ex->un.string.str, '"'); | |
| if( pnt != NULL ) | |
| { | |
| *pnt = '\0'; | |
| } | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_USConstExpr(unsigned int value) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_CONST; | |
| ex->un.u_const.value = value; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_BinopExpr(int operator_type, struct expr * exp1, struct expr * exp2) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_BINOP; | |
| ex->un.binop.binop_type = operator_type; | |
| ex->un.binop.exp1 = exp1; | |
| ex->un.binop.exp2 = exp2; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_UnopExpr(int operator_type, struct expr * exp1) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_UNOP; | |
| ex->un.unop.unop_type = operator_type; | |
| ex->un.unop.exp1 = exp1; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_StructExpr(struct expr * exp, const char * element) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_STRUCT; | |
| ex->un.structure.exp1 = exp; | |
| ex->un.structure.element_name = element; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_StructPExpr(struct expr * exp, const char * element) | |
| { | |
| struct expr * ex; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_PSTRUCT; | |
| ex->un.structure.exp1 = exp; | |
| ex->un.structure.element_name = element; | |
| return ex; | |
| } | |
| struct expr * | |
| DEBUG_CallExpr(const char * funcname, int nargs, ...) | |
| { | |
| struct expr * ex; | |
| va_list ap; | |
| int i; | |
| ex = DEBUG_GetFreeExpr(); | |
| ex->type = EXPR_TYPE_CALL; | |
| ex->un.call.funcname = funcname; | |
| ex->un.call.nargs = nargs; | |
| va_start(ap, nargs); | |
| for(i=0; i < nargs; i++) | |
| { | |
| ex->un.call.arg[i] = va_arg(ap, struct expr *); | |
| } | |
| va_end(ap); | |
| return ex; | |
| } | |
| DBG_VALUE DEBUG_EvalExpr(struct expr * exp) | |
| { | |
| DBG_VALUE rtn; | |
| int i; | |
| DBG_VALUE exp1; | |
| DBG_VALUE exp2; | |
| unsigned int cexp[5]; | |
| int scale1; | |
| int scale2; | |
| int scale3; | |
| struct datatype * type1; | |
| struct datatype * type2; | |
| rtn.type = NULL; | |
| rtn.cookie = DV_INVALID; | |
| rtn.addr.off = 0; | |
| rtn.addr.seg = 0; | |
| switch(exp->type) | |
| { | |
| case EXPR_TYPE_CAST: | |
| rtn = DEBUG_EvalExpr(exp->un.cast.expr); | |
| rtn.type = exp->un.cast.cast; | |
| if (DEBUG_GetType(rtn.type) == DT_POINTER) | |
| rtn.cookie = DV_TARGET; | |
| break; | |
| case EXPR_TYPE_STRING: | |
| rtn.type = DEBUG_TypeString; | |
| rtn.cookie = DV_HOST; | |
| rtn.addr.off = (unsigned int) &exp->un.string.str; | |
| rtn.addr.seg = 0; | |
| break; | |
| case EXPR_TYPE_CONST: | |
| rtn.type = DEBUG_TypeIntConst; | |
| rtn.cookie = DV_HOST; | |
| rtn.addr.off = (unsigned int) &exp->un.constant.value; | |
| rtn.addr.seg = 0; | |
| break; | |
| case EXPR_TYPE_US_CONST: | |
| rtn.type = DEBUG_TypeUSInt; | |
| rtn.cookie = DV_HOST; | |
| rtn.addr.off = (unsigned int) &exp->un.u_const.value; | |
| rtn.addr.seg = 0; | |
| break; | |
| case EXPR_TYPE_SYMBOL: | |
| if( !DEBUG_GetSymbolValue(exp->un.symbol.name, -1, &rtn, FALSE) ) | |
| { | |
| RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); | |
| } | |
| break; | |
| case EXPR_TYPE_PSTRUCT: | |
| exp1 = DEBUG_EvalExpr(exp->un.structure.exp1); | |
| if( exp1.type == NULL ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| rtn.cookie = DV_TARGET; | |
| rtn.addr.off = DEBUG_TypeDerefPointer(&exp1, &type1); | |
| if( type1 == NULL ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| rtn.type = type1; | |
| DEBUG_FindStructElement(&rtn, exp->un.structure.element_name, | |
| &exp->un.structure.result); | |
| break; | |
| case EXPR_TYPE_STRUCT: | |
| exp1 = DEBUG_EvalExpr(exp->un.structure.exp1); | |
| if( exp1.type == NULL ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| rtn = exp1; | |
| DEBUG_FindStructElement(&rtn, exp->un.structure.element_name, | |
| &exp->un.structure.result); | |
| break; | |
| case EXPR_TYPE_CALL: | |
| /* | |
| * First, evaluate all of the arguments. If any of them are not | |
| * evaluable, then bail. | |
| */ | |
| for(i=0; i < exp->un.call.nargs; i++) | |
| { | |
| exp1 = DEBUG_EvalExpr(exp->un.call.arg[i]); | |
| if( exp1.type == NULL ) | |
| { | |
| return rtn; | |
| } | |
| cexp[i] = DEBUG_GetExprValue(&exp1, NULL); | |
| } | |
| /* | |
| * Now look up the address of the function itself. | |
| */ | |
| if( !DEBUG_GetSymbolValue(exp->un.call.funcname, -1, &rtn, FALSE ) ) | |
| { | |
| RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); | |
| } | |
| #if 0 | |
| /* FIXME: NEWDBG NIY */ | |
| /* Anyway, I wonder how this could work depending on the calling order of | |
| * the function (cdecl vs pascal for example) | |
| */ | |
| int (*fptr)(); | |
| fptr = (int (*)()) rtn.addr.off; | |
| switch(exp->un.call.nargs) | |
| { | |
| case 0: | |
| exp->un.call.result = (*fptr)(); | |
| break; | |
| case 1: | |
| exp->un.call.result = (*fptr)(cexp[0]); | |
| break; | |
| case 2: | |
| exp->un.call.result = (*fptr)(cexp[0], cexp[1]); | |
| break; | |
| case 3: | |
| exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2]); | |
| break; | |
| case 4: | |
| exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3]); | |
| break; | |
| case 5: | |
| exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3], cexp[4]); | |
| break; | |
| } | |
| #else | |
| DEBUG_Printf(DBG_CHN_MESG, "Function call no longer implemented\n"); | |
| /* would need to set up a call to this function, and then restore the current | |
| * context afterwards... | |
| */ | |
| exp->un.call.result = 0; | |
| #endif | |
| rtn.type = DEBUG_TypeInt; | |
| rtn.cookie = DV_HOST; | |
| rtn.addr.off = (unsigned int) &exp->un.call.result; | |
| break; | |
| case EXPR_TYPE_INTVAR: | |
| { | |
| DBG_INTVAR* div = DEBUG_GetIntVar(exp->un.intvar.name); | |
| if (!div) RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); | |
| rtn.cookie = DV_HOST; | |
| rtn.type = div->type; | |
| rtn.addr.off = (unsigned int)div->pval; | |
| /* EPP FIXME rtn.addr.seg = ?? */ | |
| } | |
| break; | |
| case EXPR_TYPE_BINOP: | |
| exp1 = DEBUG_EvalExpr(exp->un.binop.exp1); | |
| exp2 = DEBUG_EvalExpr(exp->un.binop.exp2); | |
| rtn.cookie = DV_HOST; | |
| if( exp1.type == NULL || exp2.type == NULL ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| if( exp1.type == DEBUG_TypeIntConst && exp2.type == DEBUG_TypeIntConst ) | |
| { | |
| rtn.type = exp1.type; | |
| } | |
| else | |
| { | |
| rtn.type = DEBUG_TypeInt; | |
| } | |
| rtn.addr.seg = 0; | |
| rtn.addr.off = (unsigned int) &exp->un.binop.result; | |
| switch(exp->un.binop.binop_type) | |
| { | |
| case EXP_OP_ADD: | |
| type1 = DEBUG_GetPointerType(exp1.type); | |
| type2 = DEBUG_GetPointerType(exp2.type); | |
| scale1 = 1; | |
| scale2 = 1; | |
| if( type1 != NULL && type2 != NULL ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| else if( type1 != NULL ) | |
| { | |
| scale2 = DEBUG_GetObjectSize(type1); | |
| rtn.type = exp1.type; | |
| } | |
| else if( type2 != NULL ) | |
| { | |
| scale1 = DEBUG_GetObjectSize(type2); | |
| rtn.type = exp2.type; | |
| } | |
| exp->un.binop.result = (VAL(exp1) * scale1 + scale2 * VAL(exp2)); | |
| break; | |
| case EXP_OP_SUB: | |
| type1 = DEBUG_GetPointerType(exp1.type); | |
| type2 = DEBUG_GetPointerType(exp2.type); | |
| scale1 = 1; | |
| scale2 = 1; | |
| scale3 = 1; | |
| if( type1 != NULL && type2 != NULL ) | |
| { | |
| if( type1 != type2 ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| scale3 = DEBUG_GetObjectSize(type1); | |
| } | |
| else if( type1 != NULL ) | |
| { | |
| scale2 = DEBUG_GetObjectSize(type1); | |
| rtn.type = exp1.type; | |
| } | |
| else if( type2 != NULL ) | |
| { | |
| scale1 = DEBUG_GetObjectSize(type2); | |
| rtn.type = exp2.type; | |
| } | |
| exp->un.binop.result = (VAL(exp1) - VAL(exp2)) / scale3; | |
| break; | |
| case EXP_OP_SEG: | |
| rtn.cookie = DV_TARGET; | |
| rtn.type = NULL; | |
| rtn.addr.seg = VAL(exp1); | |
| rtn.addr.off = VAL(exp2); | |
| break; | |
| case EXP_OP_LOR: | |
| exp->un.binop.result = (VAL(exp1) || VAL(exp2)); | |
| break; | |
| case EXP_OP_LAND: | |
| exp->un.binop.result = (VAL(exp1) && VAL(exp2)); | |
| break; | |
| case EXP_OP_OR: | |
| exp->un.binop.result = (VAL(exp1) | VAL(exp2)); | |
| break; | |
| case EXP_OP_AND: | |
| exp->un.binop.result = (VAL(exp1) & VAL(exp2)); | |
| break; | |
| case EXP_OP_XOR: | |
| exp->un.binop.result = (VAL(exp1) ^ VAL(exp2)); | |
| break; | |
| case EXP_OP_EQ: | |
| exp->un.binop.result = (VAL(exp1) == VAL(exp2)); | |
| break; | |
| case EXP_OP_GT: | |
| exp->un.binop.result = (VAL(exp1) > VAL(exp2)); | |
| break; | |
| case EXP_OP_LT: | |
| exp->un.binop.result = (VAL(exp1) < VAL(exp2)); | |
| break; | |
| case EXP_OP_GE: | |
| exp->un.binop.result = (VAL(exp1) >= VAL(exp2)); | |
| break; | |
| case EXP_OP_LE: | |
| exp->un.binop.result = (VAL(exp1) <= VAL(exp2)); | |
| break; | |
| case EXP_OP_NE: | |
| exp->un.binop.result = (VAL(exp1) != VAL(exp2)); | |
| break; | |
| case EXP_OP_SHL: | |
| exp->un.binop.result = ((unsigned) VAL(exp1) << VAL(exp2)); | |
| break; | |
| case EXP_OP_SHR: | |
| exp->un.binop.result = ((unsigned) VAL(exp1) >> VAL(exp2)); | |
| break; | |
| case EXP_OP_MUL: | |
| exp->un.binop.result = (VAL(exp1) * VAL(exp2)); | |
| break; | |
| case EXP_OP_DIV: | |
| if( VAL(exp2) == 0 ) | |
| { | |
| RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL); | |
| } | |
| exp->un.binop.result = (VAL(exp1) / VAL(exp2)); | |
| break; | |
| case EXP_OP_REM: | |
| if( VAL(exp2) == 0 ) | |
| { | |
| RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL); | |
| } | |
| exp->un.binop.result = (VAL(exp1) % VAL(exp2)); | |
| break; | |
| case EXP_OP_ARR: | |
| DEBUG_ArrayIndex(&exp1, &rtn, VAL(exp2)); | |
| break; | |
| default: | |
| RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); | |
| break; | |
| } | |
| break; | |
| case EXPR_TYPE_UNOP: | |
| exp1 = DEBUG_EvalExpr(exp->un.unop.exp1); | |
| rtn.cookie = DV_HOST; | |
| if( exp1.type == NULL ) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| rtn.addr.seg = 0; | |
| rtn.addr.off = (unsigned int) &exp->un.unop.result; | |
| if( exp1.type == DEBUG_TypeIntConst ) | |
| { | |
| rtn.type = exp1.type; | |
| } | |
| else | |
| { | |
| rtn.type = DEBUG_TypeInt; | |
| } | |
| switch(exp->un.unop.unop_type) | |
| { | |
| case EXP_OP_NEG: | |
| exp->un.unop.result = -VAL(exp1); | |
| break; | |
| case EXP_OP_NOT: | |
| exp->un.unop.result = !VAL(exp1); | |
| break; | |
| case EXP_OP_LNOT: | |
| exp->un.unop.result = ~VAL(exp1); | |
| break; | |
| case EXP_OP_DEREF: | |
| /* FIXME: this is currently buggy. | |
| * there is no way to tell were the deref:ed value is... | |
| * for example: | |
| * x is a pointer to struct s, x being on the stack | |
| * => exp1 is target, result is target | |
| * x is a pointer to struct s, x being optimized into a reg | |
| * => exp1 is host, result is target | |
| * x is a pointer to internal variable x | |
| * => exp1 is host, result is host | |
| * so we force DV_TARGET, because dereferencing pointers to | |
| * internal variables is very unlikely. a correct fix would be | |
| * rather large. | |
| */ | |
| rtn.cookie = DV_TARGET; | |
| rtn.addr.off = (unsigned int) DEBUG_TypeDerefPointer(&exp1, &rtn.type); | |
| if (!rtn.type) | |
| { | |
| RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); | |
| } | |
| break; | |
| case EXP_OP_FORCE_DEREF: | |
| rtn.cookie = exp1.cookie; | |
| rtn.addr.seg = exp1.addr.seg; | |
| if (exp1.cookie == DV_TARGET) | |
| DEBUG_READ_MEM((void*)exp1.addr.off, &rtn.addr.off, sizeof(rtn.addr.off)); | |
| else | |
| memcpy(&rtn.addr.off, (void*)exp1.addr.off, sizeof(rtn.addr.off)); | |
| break; | |
| case EXP_OP_ADDR: | |
| /* FIXME: even for a 16 bit entity ? */ | |
| rtn.type = DEBUG_FindOrMakePointerType(exp1.type); | |
| exp->un.unop.result = exp1.addr.off; | |
| break; | |
| default: | |
| RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); | |
| } | |
| break; | |
| default: | |
| DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression (%d).\n", exp->type); | |
| RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); | |
| break; | |
| } | |
| assert(rtn.cookie == DV_TARGET || rtn.cookie == DV_HOST); | |
| return rtn; | |
| } | |
| int | |
| DEBUG_DisplayExpr(const struct expr * exp) | |
| { | |
| int i; | |
| switch(exp->type) | |
| { | |
| case EXPR_TYPE_CAST: | |
| DEBUG_Printf(DBG_CHN_MESG, "(("); | |
| DEBUG_PrintTypeCast(exp->un.cast.cast); | |
| DEBUG_Printf(DBG_CHN_MESG, ")"); | |
| DEBUG_DisplayExpr(exp->un.cast.expr); | |
| DEBUG_Printf(DBG_CHN_MESG, ")"); | |
| break; | |
| case EXPR_TYPE_INTVAR: | |
| DEBUG_Printf(DBG_CHN_MESG, "$%s", exp->un.intvar.name); | |
| break; | |
| case EXPR_TYPE_US_CONST: | |
| DEBUG_Printf(DBG_CHN_MESG, "%ud", exp->un.u_const.value); | |
| break; | |
| case EXPR_TYPE_CONST: | |
| DEBUG_Printf(DBG_CHN_MESG, "%d", exp->un.u_const.value); | |
| break; | |
| case EXPR_TYPE_STRING: | |
| DEBUG_Printf(DBG_CHN_MESG, "\"%s\"", exp->un.string.str); | |
| break; | |
| case EXPR_TYPE_SYMBOL: | |
| DEBUG_Printf(DBG_CHN_MESG, "%s" , exp->un.symbol.name); | |
| break; | |
| case EXPR_TYPE_PSTRUCT: | |
| DEBUG_DisplayExpr(exp->un.structure.exp1); | |
| DEBUG_Printf(DBG_CHN_MESG, "->%s", exp->un.structure.element_name); | |
| break; | |
| case EXPR_TYPE_STRUCT: | |
| DEBUG_DisplayExpr(exp->un.structure.exp1); | |
| DEBUG_Printf(DBG_CHN_MESG, ".%s", exp->un.structure.element_name); | |
| break; | |
| case EXPR_TYPE_CALL: | |
| DEBUG_Printf(DBG_CHN_MESG, "%s(",exp->un.call.funcname); | |
| for(i=0; i < exp->un.call.nargs; i++) | |
| { | |
| DEBUG_DisplayExpr(exp->un.call.arg[i]); | |
| if( i != exp->un.call.nargs - 1 ) | |
| { | |
| DEBUG_Printf(DBG_CHN_MESG, ", "); | |
| } | |
| } | |
| DEBUG_Printf(DBG_CHN_MESG, ")"); | |
| break; | |
| case EXPR_TYPE_BINOP: | |
| DEBUG_Printf(DBG_CHN_MESG, "( "); | |
| DEBUG_DisplayExpr(exp->un.binop.exp1); | |
| switch(exp->un.binop.binop_type) | |
| { | |
| case EXP_OP_ADD: | |
| DEBUG_Printf(DBG_CHN_MESG, " + "); | |
| break; | |
| case EXP_OP_SUB: | |
| DEBUG_Printf(DBG_CHN_MESG, " - "); | |
| break; | |
| case EXP_OP_SEG: | |
| DEBUG_Printf(DBG_CHN_MESG, ":"); | |
| break; | |
| case EXP_OP_LOR: | |
| DEBUG_Printf(DBG_CHN_MESG, " || "); | |
| break; | |
| case EXP_OP_LAND: | |
| DEBUG_Printf(DBG_CHN_MESG, " && "); | |
| break; | |
| case EXP_OP_OR: | |
| DEBUG_Printf(DBG_CHN_MESG, " | "); | |
| break; | |
| case EXP_OP_AND: | |
| DEBUG_Printf(DBG_CHN_MESG, " & "); | |
| break; | |
| case EXP_OP_XOR: | |
| DEBUG_Printf(DBG_CHN_MESG, " ^ "); | |
| break; | |
| case EXP_OP_EQ: | |
| DEBUG_Printf(DBG_CHN_MESG, " == "); | |
| break; | |
| case EXP_OP_GT: | |
| DEBUG_Printf(DBG_CHN_MESG, " > "); | |
| break; | |
| case EXP_OP_LT: | |
| DEBUG_Printf(DBG_CHN_MESG, " < "); | |
| break; | |
| case EXP_OP_GE: | |
| DEBUG_Printf(DBG_CHN_MESG, " >= "); | |
| break; | |
| case EXP_OP_LE: | |
| DEBUG_Printf(DBG_CHN_MESG, " <= "); | |
| break; | |
| case EXP_OP_NE: | |
| DEBUG_Printf(DBG_CHN_MESG, " != "); | |
| break; | |
| case EXP_OP_SHL: | |
| DEBUG_Printf(DBG_CHN_MESG, " << "); | |
| break; | |
| case EXP_OP_SHR: | |
| DEBUG_Printf(DBG_CHN_MESG, " >> "); | |
| break; | |
| case EXP_OP_MUL: | |
| DEBUG_Printf(DBG_CHN_MESG, " * "); | |
| break; | |
| case EXP_OP_DIV: | |
| DEBUG_Printf(DBG_CHN_MESG, " / "); | |
| break; | |
| case EXP_OP_REM: | |
| DEBUG_Printf(DBG_CHN_MESG, " %% "); | |
| break; | |
| case EXP_OP_ARR: | |
| DEBUG_Printf(DBG_CHN_MESG, "["); | |
| break; | |
| default: | |
| break; | |
| } | |
| DEBUG_DisplayExpr(exp->un.binop.exp2); | |
| if( exp->un.binop.binop_type == EXP_OP_ARR ) | |
| { | |
| DEBUG_Printf(DBG_CHN_MESG, "]"); | |
| } | |
| DEBUG_Printf(DBG_CHN_MESG, " )"); | |
| break; | |
| case EXPR_TYPE_UNOP: | |
| switch(exp->un.unop.unop_type) | |
| { | |
| case EXP_OP_NEG: | |
| DEBUG_Printf(DBG_CHN_MESG, "-"); | |
| break; | |
| case EXP_OP_NOT: | |
| DEBUG_Printf(DBG_CHN_MESG, "!"); | |
| break; | |
| case EXP_OP_LNOT: | |
| DEBUG_Printf(DBG_CHN_MESG, "~"); | |
| break; | |
| case EXP_OP_DEREF: | |
| DEBUG_Printf(DBG_CHN_MESG, "*"); | |
| break; | |
| case EXP_OP_ADDR: | |
| DEBUG_Printf(DBG_CHN_MESG, "&"); | |
| break; | |
| } | |
| DEBUG_DisplayExpr(exp->un.unop.exp1); | |
| break; | |
| default: | |
| DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression.\n"); | |
| RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); | |
| break; | |
| } | |
| return TRUE; | |
| } | |
| struct expr * | |
| DEBUG_CloneExpr(const struct expr * exp) | |
| { | |
| int i; | |
| struct expr * rtn; | |
| rtn = (struct expr *) DBG_alloc(sizeof(struct expr)); | |
| /* | |
| * First copy the contents of the expression itself. | |
| */ | |
| *rtn = *exp; | |
| switch(exp->type) | |
| { | |
| case EXPR_TYPE_CAST: | |
| rtn->un.cast.expr = DEBUG_CloneExpr(exp->un.cast.expr); | |
| break; | |
| case EXPR_TYPE_INTVAR: | |
| rtn->un.intvar.name = DBG_strdup(exp->un.intvar.name); | |
| break; | |
| case EXPR_TYPE_US_CONST: | |
| case EXPR_TYPE_CONST: | |
| break; | |
| case EXPR_TYPE_STRING: | |
| rtn->un.string.str = DBG_strdup(exp->un.string.str); | |
| break; | |
| case EXPR_TYPE_SYMBOL: | |
| rtn->un.symbol.name = DBG_strdup(exp->un.symbol.name); | |
| break; | |
| case EXPR_TYPE_PSTRUCT: | |
| case EXPR_TYPE_STRUCT: | |
| rtn->un.structure.exp1 = DEBUG_CloneExpr(exp->un.structure.exp1); | |
| rtn->un.structure.element_name = DBG_strdup(exp->un.structure.element_name); | |
| break; | |
| case EXPR_TYPE_CALL: | |
| for(i=0; i < exp->un.call.nargs; i++) | |
| { | |
| rtn->un.call.arg[i] = DEBUG_CloneExpr(exp->un.call.arg[i]); | |
| } | |
| rtn->un.call.funcname = DBG_strdup(exp->un.call.funcname); | |
| break; | |
| case EXPR_TYPE_BINOP: | |
| rtn->un.binop.exp1 = DEBUG_CloneExpr(exp->un.binop.exp1); | |
| rtn->un.binop.exp2 = DEBUG_CloneExpr(exp->un.binop.exp2); | |
| break; | |
| case EXPR_TYPE_UNOP: | |
| rtn->un.unop.exp1 = DEBUG_CloneExpr(exp->un.unop.exp1); | |
| break; | |
| default: | |
| DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression.\n"); | |
| RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); | |
| break; | |
| } | |
| return rtn; | |
| } | |
| /* | |
| * Recursively go through an expression tree and free all memory associated | |
| * with it. | |
| */ | |
| int | |
| DEBUG_FreeExpr(struct expr * exp) | |
| { | |
| int i; | |
| switch(exp->type) | |
| { | |
| case EXPR_TYPE_CAST: | |
| DEBUG_FreeExpr(exp->un.cast.expr); | |
| break; | |
| case EXPR_TYPE_INTVAR: | |
| DBG_free((char *) exp->un.intvar.name); | |
| break; | |
| case EXPR_TYPE_US_CONST: | |
| case EXPR_TYPE_CONST: | |
| break; | |
| case EXPR_TYPE_STRING: | |
| DBG_free((char *) exp->un.string.str); | |
| break; | |
| case EXPR_TYPE_SYMBOL: | |
| DBG_free((char *) exp->un.symbol.name); | |
| break; | |
| case EXPR_TYPE_PSTRUCT: | |
| case EXPR_TYPE_STRUCT: | |
| DEBUG_FreeExpr(exp->un.structure.exp1); | |
| DBG_free((char *) exp->un.structure.element_name); | |
| break; | |
| case EXPR_TYPE_CALL: | |
| for(i=0; i < exp->un.call.nargs; i++) | |
| { | |
| DEBUG_FreeExpr(exp->un.call.arg[i]); | |
| } | |
| DBG_free((char *) exp->un.call.funcname); | |
| break; | |
| case EXPR_TYPE_BINOP: | |
| DEBUG_FreeExpr(exp->un.binop.exp1); | |
| DEBUG_FreeExpr(exp->un.binop.exp2); | |
| break; | |
| case EXPR_TYPE_UNOP: | |
| DEBUG_FreeExpr(exp->un.unop.exp1); | |
| break; | |
| default: | |
| DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression.\n"); | |
| RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); | |
| break; | |
| } | |
| DBG_free(exp); | |
| return TRUE; | |
| } |