共计 10297 个字符,预计需要花费 26 分钟才能阅读完成。
表达式解析中比较重要的是表达式树中操作符的插入,需要比较优先级:
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};
}
到此,语法分析的基本框架已成。
正文完