乐趣区

SharpC-A-C-Interpreter-In-C-1010

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

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};
}

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

退出移动版