Esempio n. 1
0
File: Expr.cs Progetto: alexfordc/Au
        void __ExprCalcOperatorBinary(_OP op, ref _EVAL A, _EVAL B)
        {
            if (A.op < B.op)
            {
                A.op = B.op;
            }
            switch (A.op)
            {
            case _OP.OperandInt:
                A.value = (ulong)__ExprCalcOperatorBinary(op, (int)A.value, (int)B.value);
                break;

            case _OP.OperandUint:
                A.value = __ExprCalcOperatorBinary(op, (uint)A.value, (uint)B.value);
                break;

            case _OP.OperandLong:
                A.value = (ulong)__ExprCalcOperatorBinary(op, (long)A.value, (long)B.value);
                break;

            case _OP.OperandUlong:
                A.value = __ExprCalcOperatorBinary(op, A.value, B.value);
                break;
            }
        }
Esempio n. 2
0
File: Expr.cs Progetto: alexfordc/Au
        //int _debugNFailed;

        #region CALC_UNARY

        void __ExprCalcOperatorUnary(_OP op, ref _EVAL A)
        {
            switch (A.op)
            {
            case _OP.OperandInt: A.value = (ulong)__ExprCalcOperatorUnary(op, (int)A.value); break;

            case _OP.OperandUint: A.value = __ExprCalcOperatorUnary(op, (uint)A.value); break;

            case _OP.OperandLong: A.value = (ulong)__ExprCalcOperatorUnary(op, (long)A.value); break;

            case _OP.OperandUlong: A.value = __ExprCalcOperatorUnary(op, A.value); break;
            }
        }
Esempio n. 3
0
File: Expr.cs Progetto: alexfordc/Au
        bool __ExprCalcCast(int i, ref _EVAL A)
        {
            //AOutput.Write(_tok[i]);

            _Symbol x;

            if (!_TryFindSymbol(i, out x, false))
            {
                //AOutput.Write(_tok[i]); //0 in SDK
                //_Err(i, "unknown");
                return(false);
            }
            if (0 != _Unalias(i, ref x) || _TokIsChar(i + 1, '*'))
            {
                //support expressions like '#define RT_BITMAP (LPWSTR)((ULONG_PTR)((WORD)(2)))'
                if (A.op <= _OP.OperandUint)
                {
                    A.op = _OP.OperandInt;
                    return(true);
                }
                //_Err(i, "stop"); //0 in SDK
                return(false);
            }
            var ct = x as _CppType;

            if (ct == null)
            {
                //support LPARAM, HWND
                if (A.op > _OP.OperandUint)
                {
                    return(false);                                       //0 in SDK
                }
                if (x == _sym_LPARAM || x == _sym_Wnd)
                {
                    return(true);
                }
                //support enum, callback
                if (x is _Enum || x is _Callback)
                {
                    return(true);
                }
                //_Err(i, "stop 2"); //0 in SDK
                return(false);
            }

            switch (ct.sizeBytesCpp)
            {
            case 8:
                if (ct.csTypename[0] == 'd')
                {
                    return(false);                            //double
                }
                if (ct.csTypename[0] == 'I')                  //IntPtr
                //AOutput.Write(_DebugGetLine(i));
                {
                    if (A.op > _OP.OperandUint)
                    {
                        return(false);         //0 in SDK
                    }
                    break;                     //let be the same type as in 32-bit mode (no long). All in SDK are like #define HKEY_CURRENT_USER (IntPtr)0x80000001.
                }
                A.op = ct.isUnsigned ? _OP.OperandUlong : _OP.OperandLong;
                return(true);

            case 4:
                if (ct.csTypename[0] == 'f')
                {
                    return(false);                                        //float
                }
                A.value = (uint)A.value;
                break;

            case 2:
                A.value = (ushort)A.value;
                break;

            case 1:
                if (ct.csTypename == "bool")
                {
                    A.value = A.value == 0U ? 0U : 1U;
                }
                else
                {
                    A.value = (byte)A.value;
                }
                break;

            default: return(false);
            }

            A.op = ct.isUnsigned ? _OP.OperandUint : _OP.OperandInt;
            return(true);
        }
Esempio n. 4
0
File: Expr.cs Progetto: alexfordc/Au
 void __ExprDebugOutValue(_EVAL v)
 {
     AOutput.Write($"    {v.op}, { __ExprValueToString(v.value, v.op)}");
 }
Esempio n. 5
0
File: Expr.cs Progetto: alexfordc/Au
        _ExpressionResult _Expression(int iFrom, int iTo, string debugConstName = null)
        {
            Debug.Assert(iTo > iFrom);

            int nTok = iTo - iFrom, iLast = iTo - 1;

            string sValue, sType; bool isHex = false;

            //if(debugConstName == "[]") return new _ExpressionResult(_TokToString(iFrom, iTo), null, true);
            //AOutput.Write($"{debugConstName} {_TokToString(iFrom, iTo)}");

            //Unenclose whole expression (not parts).

            while (nTok >= 3 && _TokIsChar(iFrom, '(') && _TokIsChar(iLast, ')'))
            {
                if (nTok == 3 || _SkipEnclosed(iFrom) == iLast)
                {
                    iFrom++; iLast--; iTo--; nTok -= 2;
                }
                else
                {
                    break;
                }
            }

            //Simple cases.

            if (nTok == 1)
            {
                ulong value; _OP type;

                if (_TokIsNumber(iFrom))
                {
                    if (__ExprNumber(iFrom, out value, out type, ref isHex))
                    {
                        type   = __ExprMakeUintIfHex(type, isHex);
                        sValue = __ExprValueToString(value, type);
                        sType  = __ExprTypeToString(type);
                        return(new _ExpressionResult(sValue, sType, false, value));
                    }
                    else
                    {
                        sValue = _TokToString(iFrom);
                        sType  = sValue.Ends("f", true) ? "float" : "double";
                        return(new _ExpressionResult(sValue, sType, false));
                    }
                }

                if (_TokIsChar(iFrom, '\"'))
                {
                    return(new _ExpressionResult(_TokToString(iFrom), "string", false));
                }
                if (_TokIsChar(iFrom, '\''))
                {
                    //is like 'ABCD'?
                    int len = _tok[iFrom].len - 2;
                    if (len > 1 && len <= 4)
                    {
                        char *s = T(iFrom) + 1;
                        if (*s != '\\')
                        {
                            //AOutput.Write(_DebugGetLine(iFrom));
                            uint k = 0; for (int j = 0; j < len; j++)
                            {
                                k = (k << 8) | ((uint)s[j] & 0xff);
                            }
                            return(new _ExpressionResult($"0x{k:X}", "uint", false, k));
                        }
                    }
                    //string k=_TokToString(iFrom).Re
                    return(new _ExpressionResult(_TokToString(iFrom), "char", false));
                }

                if (_TokIsIdent(iFrom))
                {
                    if (_EnumFindValue(iFrom, out value, out type))
                    {
                        sValue = __ExprValueToString(value, type);
                        sType  = __ExprTypeToString(type);
                        return(new _ExpressionResult(sValue, sType, false, value));
                    }

                    //AOutput.Write($"<><c 0xff0000>{_TokToString(iFrom, iTo)}</c>");
                }
                else
                {
                    //AOutput.Write($"<><c 0xff0000>{_TokToString(iFrom, iTo)}</c>"); //0 in SDK
                }

                return(new _ExpressionResult(_TokToString(iFrom), null, true));
            }

            //Calculate expression.

            //OutList(debugConstName, _TokToString(iFrom, iTo));

            //Part 1 - convert the expression from normal infix form to RPN form which is easy to calculate.
            //Use the shunting-yard algorithm: https://en.wikipedia.org/wiki/Shunting-yard_algorithm
            //Put operands and operators in _eRPN, which is the "output queue" of the algorithm.

            int  nRPN = 0;           //number of elements in the output queue
            int  nOp  = 0;           //number of elements in the operator stack
            int  i;
            bool wasOperand = false;

            ////Debug
            //if(debugConstName == "WTS_CURRENT_SERVER") {
            //	AOutput.Write(debugConstName);
            //	int stop = 0;
            //}

            for (i = iFrom; i < iTo; i++)
            {
                int  iTok = i;
                _OP  op;
                char c = *T(i);

                if (_IsCharIdent(c) || c == '\'')                  //digit, identifier or 'character'
                {
                    if (wasOperand)
                    {
                        goto gFail;                                //cannot be 2 operands
                    }
                    wasOperand = true;

                    //If the token is a number, then add it to the output queue.

                    ulong value; _OP type = _OP.OperandInt;

                    if (_IsCharDigit(c))                      //number
                    {
                        if (!__ExprNumber(i, out value, out type, ref isHex))
                        {
                            //_Err(i, "bad number"); //0 in SDK
                            goto gFail;
                        }
                    }
                    else if (c == '\'')
                    {
                        char *s   = T(i) + 1;
                        int   len = _tok[i].len - 2;
                        if (len > 1)
                        {
                            if (len == 2 && *s == '\\')
                            {
                                s++;
                            }
                            else
                            {
                                goto gFail;
                            }
                        }
                        value = *s;
                    }
                    else                         //identifier
                    {
                        if (_TokIs(i, "sizeof"))
                        {
                            if (!_TokIsChar(++i, '('))
                            {
                                goto gFail;
                            }
                            int rightParen = __ExprIsType(++i);
                            if (rightParen != i + 1)
                            {
                                goto gFail;                                                 //if not like a type, or with *
                            }
                            if (!__ExprSizeof(i, out value))
                            {
                                goto gFail;
                            }
                            i++;
                        }
                        else
                        {
                            if (!_EnumFindValue(i, out value, out type))
                            {
                                goto gFail;
                            }
                        }
                    }

                    _eRPN[nRPN++] = new _EVAL(i, type, value);
                }
                else if (_IsCharOperator(c) || c == '(')                    //operator or cast or (
                {
                    if (c == '(')
                    {
                        //is cast?
                        int  rightParen = __ExprIsType(i + 1);
                        bool isCast     = rightParen > 0;
                        if (isCast && rightParen - i == 2 && _enumValues.ContainsKey(_tok[i + 1]))
                        {
                            isCast = false;                  //is '(enumValue)'?
                        }
                        if (isCast)                          //cast
                        {
                            iTok = i + 1;
                            i    = rightParen;
                            op   = _OP.Cast;

                            //cast is an operator
                        }
                        else
                        {
                            iTok = i;
                            op   = _OP.LeftParen;
                        }
                    }
                    else
                    {
                        char c2 = *T(i + 1);
                        op = 0;

                        if (wasOperand)                        //this must be a binary operator
                        {
                            //note: cannot be +=, ++ etc because they can be used only with variables, not with constants.

                            wasOperand = false;
                            switch (c)
                            {
                            case '+': op = _OP.Plus; break;

                            case '-': op = _OP.Minus; break;

                            case '*': op = _OP.Mul; break;

                            case '/': op = _OP.Div; break;

                            case '%': op = _OP.Mod; break;

                            case '&':
                                if (c2 == '&')
                                {
                                    i++; op = _OP.LogAnd;
                                }
                                else
                                {
                                    op = _OP.BitAnd;
                                }
                                break;

                            case '|':
                                if (c2 == '|')
                                {
                                    i++; op = _OP.LogOr;
                                }
                                else
                                {
                                    op = _OP.BitOr;
                                }
                                break;

                            case '^': op = _OP.BitXor; break;

                            case '<':
                                if (c2 == '<')
                                {
                                    i++; op = _OP.BitLshift;
                                }
                                else if (c2 == '=')
                                {
                                    i++; op = _OP.LtEq;
                                }
                                else
                                {
                                    op = _OP.Lt;
                                }
                                break;

                            case '>':
                                if (c2 == '>')
                                {
                                    i++; op = _OP.BitRshift;
                                }
                                else if (c2 == '=')
                                {
                                    i++; op = _OP.GtEq;
                                }
                                else
                                {
                                    op = _OP.Gt;
                                }
                                break;

                            case '=':
                                if (c2 == '=')
                                {
                                    i++; op = _OP.CompareEq;
                                }
                                else
                                {
                                    goto gFail;
                                }
                                break;

                            case '!':
                                if (c2 == '=')
                                {
                                    i++; op = _OP.CompareNotEq;
                                }
                                else
                                {
                                    goto gFail;
                                }
                                break;

                            //case '?':
                            //	op = _OPERATOR.Ternary;
                            //	break;
                            default:
                                goto gFail;
                            }
                        }
                        else                             //this must be a prefix operator

                        //note: cannot be ++, & etc because they can be used only with variables, not with constants.

                        {
                            switch (c)
                            {
                            case '+': continue;

                            case '-': op = _OP.UnaryMinus; break;

                            case '!': op = _OP.UnaryLogNot; break;

                            case '~': op = _OP.UnaryBitNot; break;

                            default: goto gFail;
                            }
                        }
                    }

                    //If the token is an operator (op), then:
                    if (op != _OP.LeftParen)
                    {
                        //While there is an operator (op2) at the top of the stack, and either
                        //	op is left-associative and its precedence is less than or equal to that of op2, or
                        //	op is right associative, and has precedence less than that of o2,
                        //		pop op2 off the stack, onto the output queue.
                        for (; nOp > 0; nOp--)
                        {
                            int n   = nOp - 1;
                            _OP op2 = _eOp[n].op;
                            if (op2 == _OP.LeftParen)
                            {
                                break;                                                  //is an operator at the top of the stack?
                            }
                            bool pop = false, opRTL = (op & _OP._FlagRightToLeft) != 0;
                            int  prec1 = (int)(op & _OP._MaskPrecedence), prec2 = (int)(op2 & _OP._MaskPrecedence);
                            //OutList("  ", op, prec1, opRTL, op2, prec2);

                            if (!opRTL)
                            {
                                pop = prec1 >= prec2;                                    //op is left-associative and its precedence is less than or equal to that of op2
                            }
                            else
                            {
                                pop = prec1 > prec2;                              //op is right associative, and has precedence less than that of o2
                            }
                            if (!pop)
                            {
                                break;
                            }
                            _eRPN[nRPN++] = _eOp[n];
                        }
                    }                     //Else if the token is a left parenthesis (i.e. "("), then push it onto the stack.

                    //push op to the stack
                    _eOp[nOp++] = new _EVAL(iTok, op);
                }
                else if (c == ')')
                {
                    //If the token is a right parenthesis (i.e. ")"):
                    //	Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
                    for (; nOp > 0; nOp--)
                    {
                        int n = nOp - 1;
                        if (_eOp[n].op == _OP.LeftParen)
                        {
                            break;
                        }
                        _eRPN[nRPN++] = _eOp[n];
                    }
                    //If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
                    if (nOp == 0)
                    {
                        goto gFail;
                    }
                    //Pop the left parenthesis from the stack, but not onto the output queue.
                    nOp--;
                }
                else
                {
                    //"string" //0 in SDK
                    goto gFail;
                }
            }

            //When there are no more tokens to read:
            //	While there are still operator tokens in the stack:
            //		If the operator token on the top of the stack is a parenthesis: error, there are mismatched parentheses.
            //		Else pop the operator onto the output queue.
            for (; nOp > 0; nOp--)
            {
                int n = nOp - 1;
                if (_eOp[n].op == _OP.LeftParen)
                {
                    goto gFail;
                }
                _eRPN[nRPN++] = _eOp[n];
            }

            ////Debug
            //if(debugConstName == "WTS_CURRENT_SERVER") {
            //	var deb = new StringBuilder(debugConstName);
            //	deb.Append(" = ");
            //	deb.Append(_TokToString(iFrom, iTo));
            //	deb.Append("  -> ");
            //	for(i = 0; i < nRPN; i++) {
            //		deb.Append(" ");
            //		if(_eRPN[i].op < _OP._FirstOperator) deb.Append(_eRPN[i].value);
            //		else deb.Append(_eRPN[i].op);
            //	}
            //	AOutput.Write(deb);

            //	int stop = 0;
            //}

            //Part 2 - calculate the RPN expression.
            //Use the postfix algorithm: https://en.wikipedia.org/wiki/Reverse_Polish_notation

            int nCalc = 0;             //_eCalc stack length

            for (i = 0; i < nRPN; i++)
            {
                if (_eRPN[i].op < _OP._FirstOperator)                  //operand

                //If the token is a value (operand): push it onto the stack.
                {
                    _eCalc[nCalc++] = _eRPN[i];
                }
                else                     //operator

                //It is already known that the operator takes n arguments.
                {
                    int nOperands = (int)(_eRPN[i].op & _OP._MaskNOperands) >> 8;
                    //If there are fewer than n values on the stack: error, the user has not input sufficient values in the expression.
                    if (nCalc < nOperands)
                    {
                        goto gFail;
                    }

                    if (nOperands == 1)
                    {
                        //Pop the top n values from the stack.
                        //A = _eCalc[--nCalc]; //operand (we change it in-place without pop/push)

                        //Evaluate the operator, with the values as arguments.
                        _OP op = _eRPN[i].op;
                        if (op == _OP.Cast)
                        {
                            if (!__ExprCalcCast(_eRPN[i].iTok, ref _eCalc[nCalc - 1]))
                            {
                                goto gFail;
                            }
                        }
                        else
                        {
                            __ExprCalcOperatorUnary(op, ref _eCalc[nCalc - 1]);
                        }
                    }
                    else                         //2 operands

                    //Pop the top n values from the stack.
                    {
                        _EVAL B = _eCalc[--nCalc];                         //rigt operand
                        //A = _eCalc[--nCalc]; //left operand (we change it in-place without pop/push)

                        //Evaluate the operator, with the values as arguments.
                        __ExprCalcOperatorBinary(_eRPN[i].op, ref _eCalc[nCalc - 1], B);

                        //__ExprDebugOutValue(_eCalc[nCalc - 1]);
                    }

                    //Push the returned results, if any, back onto the stack.
                    //_eCalc[nCalc++] = A; //we change it in-place without pop/push
                }
            }

            //If there is only one value in the stack, it is the result of the calculation.
            //Otherwise, there are more values in the stack: error, the user input has too many values.
            if (nCalc != 1)
            {
                goto gFail;
            }
            _OP rType = __ExprMakeUintIfHex(_eCalc[0].op, isHex);

            sValue = __ExprValueToString(_eCalc[0].value, rType);
            sType  = __ExprTypeToString(rType);

            return(new _ExpressionResult(sValue, sType, false, _eCalc[0].value));

gFail:
            //AOutput.Write($"<><c 0xff>{debugConstName}    {_TokToString(iFrom, iTo)}</c>");
            //if(++_debugNFailed > 10) _Err(iFrom, "debug");
            return(new _ExpressionResult(_TokToString(iFrom, iTo), null, true));

            //never mind: need functions:
            //LongToHandle
            //HRESULT_FROM_WIN32

            //never mind: sizeof pointers, IntPtr, LPARAM and AWnd.
        }