表达式解析中比较重要的是表达式树中操作符的插入,需要比较优先级:

private bool AddOperatorNode(ref Expression.ExpressionNode expTree, Expression.Operator.Operator op){    Expression.ExpressionNode node = new Expression.ExpressionNode()    {        Token = op    };    if (expTree != null && expTree.Token is Expression.Operand.Operand)    {        node.LeftNode = expTree;        expTree = node;    }    else    {        if (expTree == null)        {            expTree = node;        }        else        {            if (node.Token <= expTree.Token)            {                node.LeftNode = expTree;                expTree = node;            }            else            {                Expression.ExpressionNode parent = null;                Expression.ExpressionNode root = expTree;                do                {                    // Operand ?                    if (root.Token is Expression.Operand.Operand)                    {                        if (parent != null)                        {                            parent.RightNode = node;                            node.LeftNode = root;                            break;                        }                        else                        {                            node.LeftNode = root;                            root = node;                            break;                        }                    }                    // Less priority, new node will be add to right child node                    if (root.Token <= node.Token)                    {                        if (root.RightNode == null)                        {                            root.RightNode = node;                            break;                        }                        parent = root;                        root = root.RightNode;                    }                    else                    {                        // Higher priority                        if (parent == null)                        {                            node.LeftNode = root;                            expTree = node;                        }                        else                        {                            parent.RightNode = node;                            node.LeftNode = root;                        }                        break;                    }                } while (true);            }        }    }    m_lastExpNode = node;    return true;} // func

接着是添加操作数的操作,需要对类型匹配进行验证:

private bool AddOperandNode(Context ctx, SourceCode src, ref Expression.ExpressionNode expTree, Expression.Operand.Operand op){    Expression.ExpressionNode node = new Expression.ExpressionNode()    {        Token = op    };    if (expTree == null)    {        expTree = node;        m_lastExpNode = node;        return true;    }    // Root should be operator.    if (expTree.Token is Expression.Operand.Operand)        if (!NotifyError(ctx, src.Location, ParsingErrorType.SyntaxError, "Syntax error."))             return false;    Expression.ExpressionNode root = expTree;    // Add to end of right side    while (root.RightNode != null)        root = root.RightNode;    // Check type    if (root.LeftNode != null)    {        DataTypeInfo leftDti = root.LeftNode.ResultType(ctx);        DataTypeInfo rightDti = op.GetTypeInfo(ctx);        if (leftDti != rightDti)        {            // void type has no meaning            if (leftDti.BaseType == PrimitiveDataType.VoidType && !leftDti.IsPointer)                if (!NotifyError(ctx, src.Location, ParsingErrorType.TypeError, "Incomplete type void"))                     return false;            if ((leftDti.IsPointer && (!rightDti.IsPointer && rightDti.BaseType == PrimitiveDataType.VoidType || rightDti.BaseType == PrimitiveDataType.FloatType)) ||                ((!leftDti.IsPointer && leftDti.BaseType == PrimitiveDataType.VoidType || leftDti.BaseType == PrimitiveDataType.FloatType) && rightDti.IsPointer))            {                // A warning should be cast.                NotifyWarning(ctx, src.Location, rightDti.ToString() + " will be cast to " + leftDti.ToString());             }        }    }    root.RightNode = node;    m_lastExpNode = node;    return true;}

以+操作符为例,说明操作符分析的过程:

private bool ParseExpression_Plus(Context ctx, SourceCode src, ref Expression.ExpressionNode expTree){    if (src.TestNextChar('=')) // +=    {        src.NextChar();        src.NextChar(); // skip '+='        return AddOperatorNode(ref expTree, new Expression.Operator.Binary.AddAssign());    }    else    {        if (src.TestNextChar('+')) // self ++        {            src.NextChar();            src.NextChar(); // skip '++'            if (expTree == null)            {                return AddOperatorNode(ref expTree, new Expression.Operator.Unary.PrefixIncrease());            }            else            {                if (m_lastExpNode == null || (m_lastExpNode != null && m_lastExpNode.Token is Expression.Operator.Operator)) //                 {                    return AddOperatorNode(ref expTree, new Expression.Operator.Unary.PrefixIncrease());                }                else                    return AddOperatorNode(ref expTree, new Expression.Operator.Unary.PostfixIncrease());            }        }        else        {            src.NextChar(); // skip '+'            if (m_lastExpNode == null || (m_lastExpNode != null && m_lastExpNode.Token is Expression.Operator.Operator))                return AddOperatorNode(ref expTree, new Expression.Operator.Unary.Plus());            else                return AddOperatorNode(ref expTree, new Expression.Operator.Binary.Add());        }    }}

最后,是获取值类型的方法:

private Expression.Operand.Value GetNumberValue(Context ctx, SourceCode src){    // Test '0x'    if (src.CurrentChar == '0' && src.TestNextChar(SourceCode.HexMark))    {        return GetHexValue(ctx, src);    }    else    {        return GetIntOrFloatValue(ctx, src);    }}private Expression.Operand.Value GetHexValue(Context ctx, SourceCode src){    int start = src.Column;    src.NextChar(); // skip '0'    src.NextChar(); // skip 'x'    do    {        if (SourceCode.IsDigit(src.CurrentChar) ||            (src.CurrentChar >= 'a' && src.CurrentChar <= 'f') ||            (src.CurrentChar >= 'A' && src.CurrentChar <= 'F'))        {            src.NextChar();        }        else        {            break;        }    } while (true);    if (src.Column - start < 3)        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid hex format."))            return null;    if (src.Column - start > 10)        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid hex format."))            return null;    string hexStr = src.Text.Substring(start + 2, src.Column - start - 2);    UInt32 val = UInt32.Parse(hexStr, System.Globalization.NumberStyles.HexNumber);    if (hexStr.Length < 3) // 0xFF        return new Expression.Operand.Value()        {            DataType = PrimitiveDataType.CharType | PrimitiveDataType.UnsignedType,            DataField = (byte)val        };    else        if (hexStr.Length < 5) // 0xFFFF            return new Expression.Operand.Value()                {                    DataType = PrimitiveDataType.ShortType | PrimitiveDataType.UnsignedType,                    DataField = (ushort)val                };        else // 0xFFFFFFFF            return new Expression.Operand.Value()            {                DataType = PrimitiveDataType.IntType,                DataField = (ushort)val            };}private Expression.Operand.Value GetIntOrFloatValue(Context ctx, SourceCode src){    bool isUnsigned = false;    int pointNum = 0;    int expNum = 0;    int floatMark = 0;    int start = src.Column;    src.NextChar(); // skip first digit    while (!src.Eof)    {        bool stop = false;        switch (src.CurrentChar)        {            case '.':                {                    pointNum++;                    if (pointNum > 1)                        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format."))                            return null;                    if (src.TestNextChar(SourceCode.ExponentialMark))                        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format."))                            return null;                    src.NextChar();                }                break;            case 'e':            case 'E':                {                    expNum++;                    if (expNum > 1)                        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format."))                            return null;                    if (src.TestNextChar(SourceCode.PlusMinusMark))                        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format."))                            return null;                    src.NextChar(); // skip 'e/E'                    src.NextChar(); // skip '+/-'                }                break;            case 'f':            case 'F':                {                    floatMark++;                    if (floatMark > 1)                        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format."))                            return null;                    if (src.Eof)                        if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format."))                            return null;                    src.NextChar(); // skip 'f/F'                    stop = true;                }                break;            default:                {                    if (!SourceCode.IsDigit(src.CurrentChar))                    {                        stop = true;                        if (src.CurrentChar == 'u' || src.CurrentChar == 'U')                        {                            if (pointNum > 0 || expNum > 0 || floatMark > 0)                            {                                if (!NotifyError(ctx, src.Location, ParsingErrorType.FormatError, "Invalid float format"))                                    return null;                            }                            src.NextChar(); // skip 'U'                            isUnsigned = true;                        }                    }                    else                        src.NextChar();                }                break;        } // switch        if (src.Eof || stop)            break;    } // while    string valStr = src.Text.Substring(start, src.Column - start);    if (pointNum > 0 || expNum > 0 || floatMark > 0)    {        float val = float.Parse(valStr);        return new Expression.Operand.Value()        {            DataType = PrimitiveDataType.FloatType,            DataField = val        };    }    else    {        int val = int.Parse(valStr);        if (val < 65535)        {            return new Expression.Operand.Value()            {                DataType = PrimitiveDataType.ShortType | (isUnsigned ? PrimitiveDataType.UnsignedType : PrimitiveDataType.SignedType),                DataField = (short)val            };        }        else            return new Expression.Operand.Value()            {                DataType = PrimitiveDataType.IntType | (isUnsigned ? PrimitiveDataType.UnsignedType : PrimitiveDataType.SignedType),                DataField = val            };    }}private Expression.Operand.Value GetCharValue(Context ctx, SourceCode src){    src.NextChar(); // skip '\''    char val = src.CurrentChar;    if (src.CurrentChar == '\\') // escape    {        src.NextChar(); // skip escape        if (m_escapeCharDict.Count == 0)        {            m_escapeCharDict.Add('a', '\a');    // Bell (alert)            m_escapeCharDict.Add('b', '\b');    // Backspace            m_escapeCharDict.Add('f', '\f');    // Formfeed            m_escapeCharDict.Add('n', '\n');    // New line            m_escapeCharDict.Add('r', '\r');    // Carriage return            m_escapeCharDict.Add('t', '\t');    // Horizontal tab            m_escapeCharDict.Add('v', '\v');    // Vertical tab            m_escapeCharDict.Add('\'', '\'');    // Single quotation mark            // m_escapeCharDict.Add('\"  Double quotation mark            m_escapeCharDict.Add('\\', '\\');   // Backslash            m_escapeCharDict.Add('?', (char)63);   // Literal question mark        }        if (SourceCode.IsDigit(src.CurrentChar)) // Digit        {            bool octal = src.CurrentChar == '0';            int start = src.Column;            while (!src.Eof && SourceCode.IsDigit(src.CurrentChar))                src.NextChar(false);            if (!src.Eof)            {                if (src.CurrentChar == '\'')                {                    string str = src.Text.Substring(start, src.Column - start);                    val  = (char)int.Parse(str, System.Globalization.NumberStyles.Integer);                }                else                    if (!NotifyError(ctx, src.Location, ParsingErrorType.SyntaxError, "Invalid char value."))                        return null;            }        }        else        {            // Hex            if (src.CurrentChar == 'x' || src.CurrentChar == 'X')            {                src.NextChar(); // skip x                int start = src.Column;                while (!src.Eof && (SourceCode.IsDigit(src.CurrentChar) || (src.CurrentChar >= 'a' && src.CurrentChar <= 'f') || (src.CurrentChar >= 'A' && src.CurrentChar <= 'F')))                    src.NextChar(false);                if (!src.Eof)                {                    if (src.CurrentChar == '\'')                    {                        string str = src.Text.Substring(start, src.Column - start);                        val = (char)int.Parse(str, System.Globalization.NumberStyles.HexNumber);                    }                    else                        if (!NotifyError(ctx, src.Location, ParsingErrorType.SyntaxError, "Invalid hexadecimal number."))                            return null;                }            }            else            {                if (!m_escapeCharDict.ContainsKey(src.CurrentChar))                    if (!NotifyError(ctx, src.Location, ParsingErrorType.SyntaxError, "Unrecognized character escape sequence."))                        return null;                val = m_escapeCharDict[src.CurrentChar];            }        }    }    src.NextChar(); // skip value field    if (src.CurrentChar != '\'')        if (!NotifyError(ctx, src.Location, ParsingErrorType.SyntaxError, "Missing close quote."))            return null;    // skip '\''    src.NextChar();    return new Expression.Operand.Value()    {        DataType = PrimitiveDataType.CharType,        DataField = (byte)val    };}private Expression.Operand.Operand GetStringValue(Context ctx, SourceCode src){    src.NextChar(); // skip '"'    int startPos = src.Column;    int startPosOfLine = src.ColumnOfCurrentLine;    int startLineNo = src.Line;    StringBuilder strBuilder = new StringBuilder();    while (!src.Eof)    {        if (src.CurrentChar == '\\')        {            src.NextChar();            src.NextChar(); // skip Escape and char        }        else            if (src.CurrentChar == '"')            {                strBuilder.Append(src.Text.Substring(startPos, src.Column - startPos));                src.NextChar(); // skip '"'                src.SkipSpace();                if (!src.Eof && src.CurrentChar == '"')                {                    src.NextChar();                    // String followed by string                    startPos = src.Column;                }                else                    break;            }            else                src.NextChar();    }    // The const variable    Variable stxConstVar = new Variable()    {        TypeInfo = new DataTypeInfo()        {            Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType,            PointerCount = 1        },        ReferenceCount = 1    };    stxConstVar.Name = Context.GetAnonymousName(stxConstVar.TypeInfo);    int byteArrayLen = Encoding.ASCII.GetByteCount(strBuilder.ToString()) + 1;    ConstantInitialize stxConstInit = new ConstantInitialize()    {        Name = Context.GetAnonymousName("const_init"),        VariableName = stxConstVar.Name,        InitialValue = new byte[byteArrayLen]    };    char[] charArray = strBuilder.ToString().ToCharArray();    Encoding.ASCII.GetBytes(charArray, 0, charArray.Length, stxConstInit.InitialValue, 0);    stxConstInit.InitialValue[byteArrayLen - 1] = 0;    ctx.GlobalContex.AddChildAtFirst(stxConstInit);    ctx.GlobalContex.AddChildAtFirst(stxConstVar);    return new Expression.Operand.ValueOfVariableReference()    {        Name = stxConstInit.VariableName    };}

到此,语法分析的基本框架已成。