コード例 #1
0
ファイル: Expr.cs プロジェクト: 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;
            }
        }
コード例 #2
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        long __ExprCalcOperatorUnary(_OP op, long A)
        {
            switch (op)
            {
            case _OP.UnaryMinus: return(-A);

            case _OP.UnaryLogNot: return(A == 0 ? 0 : 1);

            case _OP.UnaryBitNot: return(~A);
            }
            Debug.Assert(false);
            return(0);
        }
コード例 #3
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        ulong __ExprCalcOperatorUnary(_OP op, ulong A)
        {
            switch (op)
            {
            case _OP.UnaryMinus: return((ulong)-(long)A);

            case _OP.UnaryLogNot: return(A == 0U ? 0U : 1U);

            case _OP.UnaryBitNot: return(~A);
            }
            Debug.Assert(false);
            return(0);
        }
コード例 #4
0
ファイル: Expr.cs プロジェクト: 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;
            }
        }
コード例 #5
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        string __ExprValueToString(ulong value, _OP type)
        {
            Debug.Assert(type <= _OP.OperandUlong);
            switch (type)
            {
            case _OP.OperandInt: return(((int)value).ToString());

            case _OP.OperandUint: return("0x" + ((uint)value).ToString("X"));

            case _OP.OperandLong: return(((long)value).ToString());

            default: return("0x" + value.ToString("X"));
            }
        }
コード例 #6
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        string __ExprTypeToString(_OP type)
        {
            Debug.Assert(type <= _OP.OperandUlong);
            switch (type)
            {
            case _OP.OperandInt: return("int");

            case _OP.OperandUint: return("uint");

            case _OP.OperandLong: return("long");

            default: return("ulong");
            }
        }
コード例 #7
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
 _OP __ExprMakeUintIfHex(_OP type, bool isHex)
 {
     Debug.Assert(type <= _OP.OperandUlong);
     if (isHex)
     {
         if (type == _OP.OperandInt)
         {
             return(_OP.OperandUint);
         }
         if (type == _OP.OperandLong)
         {
             return(_OP.OperandUlong);
         }
     }
     return(type);
 }
コード例 #8
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        ulong __ExprCalcOperatorBinary(_OP op, ulong A, ulong B)
        {
            switch (op)
            {
            case _OP.Plus: return(A + B);

            case _OP.Minus: return(A - B);

            case _OP.Mul: return(A * B);

            case _OP.Div: return(A / B);

            case _OP.Mod: return(A % B);

            case _OP.BitLshift: return(A << (int)B);

            case _OP.BitRshift: return(A >> (int)B);

            case _OP.Lt: return(A < B ? 1U : 0U);

            case _OP.LtEq: return(A <= B ? 1U : 0U);

            case _OP.Gt: return(A > B ? 1U : 0U);

            case _OP.GtEq: return(A >= B ? 1U : 0U);

            case _OP.CompareEq: return(A == B ? 1U : 0U);

            case _OP.CompareNotEq: return(A != B ? 1U : 0U);

            case _OP.BitAnd: return(A & B);

            case _OP.BitOr: return(A | B);

            case _OP.BitXor: return(A ^ B);

            case _OP.LogAnd: return(A != 0U && B != 0U ? 1U : 0U);

            case _OP.LogOr: return(A != 0U || B != 0U ? 1U : 0U);
            }
            Debug.Assert(false);
            return(0);
        }
コード例 #9
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        int __ExprCalcOperatorBinary(_OP op, int A, int B)
        {
            switch (op)
            {
            case _OP.Plus: return(A + B);

            case _OP.Minus: return(A - B);

            case _OP.Mul: return(A * B);

            case _OP.Div: return(A / B);

            case _OP.Mod: return(A % B);

            case _OP.BitLshift: return(A << B);

            case _OP.BitRshift: return(A >> B);

            case _OP.Lt: return(A < B ? 1 : 0);

            case _OP.LtEq: return(A <= B ? 1 : 0);

            case _OP.Gt: return(A > B ? 1 : 0);

            case _OP.GtEq: return(A >= B ? 1 : 0);

            case _OP.CompareEq: return(A == B ? 1 : 0);

            case _OP.CompareNotEq: return(A != B ? 1 : 0);

            case _OP.BitAnd: return(A & B);

            case _OP.BitOr: return(A | B);

            case _OP.BitXor: return(A ^ B);

            case _OP.LogAnd: return(A != 0 && B != 0 ? 1 : 0);

            case _OP.LogOr: return(A != 0 || B != 0 ? 1 : 0);
            }
            Debug.Assert(false);
            return(0);
        }
コード例 #10
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
        bool __ExprNumber(int i, out ulong value, out _OP type, ref bool isHex)
        {
            value = 0; type = _OP.OperandInt;

            char *s = T(i), se;

            if (*s == '0')
            {
                if (s[1] == 'x' || s[1] == 'X')
                {
                    value = strtoui64(s, &se); isHex = true;
                }                                                                                           //hex
                else if (s[1] == 'b' || s[1] == 'B')
                {
                    value = strtoui64(s + 2, &se, 2); isHex = true;
                }                                                                                                       //binary constant like 0b10101010
                else
                {
                    value = strtoui64(s, &se, 8);                  //oct
                }
            }
            else
            {
                value = strtoui64(s, &se);
            }

            bool isUnsigned = false, isLong = false;

            int tlen = _tok[i].len;

            if (se < s + tlen)
            {
                if (*se == 'U' || *se == 'u')
                {
                    se++; isUnsigned = true;
                }
                if (se < s + tlen)
                {
                    if (*se == 'L' || *se == 'l')
                    {
                        se++; isLong = true;
                    }
                    if (se < s + tlen)
                    {
                        return(false);                                  //eg a floating-point number
                    }
                }
            }

            if (!isLong && value > uint.MaxValue)
            {
                isLong = true;
            }
            if (!isUnsigned)
            {
                if (isLong)
                {
                    isUnsigned = value > long.MaxValue;
                }
                else
                {
                    isUnsigned = value > int.MaxValue;
                }
            }

            if (isLong)
            {
                type = isUnsigned ? _OP.OperandUlong : _OP.OperandLong;
            }
            else if (isUnsigned)
            {
                type = _OP.OperandUint;
            }
            return(true);
        }
コード例 #11
0
ファイル: Expr.cs プロジェクト: 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.
        }
コード例 #12
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
 public _EVAL(int iTok, _OP op, ulong value)
 {
     this.iTok  = iTok;
     this.op    = op;
     this.value = value;
 }
コード例 #13
0
ファイル: Expr.cs プロジェクト: alexfordc/Au
 public _EVAL(int iTok, _OP op)
 {
     this.iTok = iTok;
     this.op   = op;
     value     = 0;
 }