表达式解析中比较重要的是表达式树中操作符的插入,需要比较优先级:
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 };}
到此,语法分析的基本框架已成。