for循环的解析:
private bool ParseControl_For(Context ctx, SourceCode src, Context.LocationInfo loc) { src.SkipSpace(); if (src.CurrentChar != '(') if (!NotifyError(ctx, GetLocation(loc.FirstLine, loc.FirstPos, src.AbsoluteLine, src.AbsolutePos), ParsingErrorType.SyntaxError, "'(' is expected.")) return false; // 括号内的代码 SourceCode stmt = GetParenthesisCode(src); List<SourceCode> stmtList = stmt.SplitStatement(); // 三部分,必须的 if (stmtList.Count != 3) if (!NotifyError(ctx, GetLocation(loc.FirstLine, loc.FirstPos, src.AbsoluteLine, src.AbsolutePos), ParsingErrorType.SyntaxError, "Syntax error.")) return false; ControlFlow.ForLoop stxFor = new ControlFlow.ForLoop() { Location = new Context.LocationInfo() { FirstLine = loc.FirstLine, FirstPos = loc.FirstPos } }; ctx.AddChild(stxFor); // 初始化 Context stxInit = new Context(); stxFor.AddChild(stxInit); if (!ParseStatement(stxInit, stmtList[0])) return false; // 条件判断 if (!ParseExpression(stxInit, stmtList[1], ref stxFor.Condition)) return false; // 迭代器 if (!ParseExpression(stxInit, stmtList[2], ref stxFor.Iterator)) return false; src.SkipSpace(); // 循环体 if (src.CurrentChar == '{') { stmt = GetBlockCode(src); } else { stmt = new SourceCode() { PosOffset = src.AbsolutePos, LineOffset = src.AbsoluteLine, Text = src.Text.Substring(src.Column) }; } Block block = new Block(); stxFor.AddChild(block); bool res = Parse(block, stmt); stxFor.Location.LastLine = stmt.AbsoluteLine; stxFor.Location.LastPos = stmt.AbsolutePos; return res; }
复杂的是switch:
private bool ParseControl_Switch(Context ctx, SourceCode src, Context.LocationInfo loc) { // Check condition src.SkipSpace(); if (src.CurrentChar != '(') if (!NotifyError(ctx, GetLocation(loc.FirstLine, loc.FirstPos, src.AbsoluteLine, src.AbsolutePos), ParsingErrorType.SyntaxError, "Expecte a '('.")) return false; ControlFlow.Switch stxSwitch = new ControlFlow.Switch() { Location = new Context.LocationInfo() { FirstLine = loc.FirstLine, FirstPos = loc.FirstPos } }; ctx.AddChild(stxSwitch); // Parse condition expression if (!ParseExpression(stxSwitch, GetParenthesisCode(src), ref stxSwitch.Condition)) { ctx.Children.RemoveAt(ctx.Children.Count - 1); return false; } // Add body stxSwitch.AddChild(new Block()); ControlFlow.Case stxDefault = new ControlFlow.Case(); // default part stxSwitch.Body.AddChild(stxDefault); // Check '{' src.SkipSpace(); if (src.CurrentChar != '{') if (!NotifyError(ctx, GetLocation(loc.FirstLine, loc.FirstPos, src.AbsoluteLine, src.AbsolutePos), ParsingErrorType.SyntaxError, "Expecte a '{'.")) return false; // Parse body SourceCode switchBodyStmt = GetBlockCode(src); Dictionary<object, bool> caseValDict = new Dictionary<object, bool>(); while (!switchBodyStmt.Eof) { switchBodyStmt.SkipSpace(); Word word = GetWord(switchBodyStmt); switch(word.Text) { case "case": { ControlFlow.Case stxCase = new ControlFlow.Case() { Location = new Context.LocationInfo() { FirstLine = word.AbsoluteLine, FirstPos = word.AbsoluteStartPos } }; switchBodyStmt.SkipSpace(); if (switchBodyStmt.CurrentChar == '\'') // char { Expression.Operand.Value charVal = GetCharValue(stxSwitch, switchBodyStmt); if (charVal == null) if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "Expecte a expression.")) return false; stxCase.Value = charVal; } else { if (SourceCode.IsDigit(switchBodyStmt.CurrentChar)) // number { stxCase.Value = GetNumberValue(ctx, switchBodyStmt); if ((stxCase.Value.GetTypeInfo(ctx).Type & PrimitiveDataType.BaseTypeMask) == PrimitiveDataType.FloatType) if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "Expression must be an integral constant value.")) return false; } else if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "Expression must have a constant value.")) return false; } if (caseValDict.ContainsKey(stxCase.Value.AsInt)) { if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "Case label value has appeared in this switch.")) return false; } else caseValDict.Add(stxCase.Value.AsInt, true); stxSwitch.Body.AddChild(stxCase); // Parse case body switchBodyStmt.SkipSpace(); if (switchBodyStmt.CurrentChar != ':') if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "identifier is undefined.")) return false; switchBodyStmt.NextChar(); // skip ':' stxCase.Location.LastLine = switchBodyStmt.AbsoluteLine; stxCase.Location.LastPos = switchBodyStmt.AbsolutePos; NotifyParsing(stxCase); stxCase.AddChild(new Block()); if (!Parse(stxCase.Body, GetCaseBodyCode(ctx, switchBodyStmt))) return false; } break; case "default": { if (stxDefault.Children.Count > 0) if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "default label has already appeared in this switch.")) return false; // Check ':' switchBodyStmt.SkipSpace(); if (switchBodyStmt.CurrentChar != ':') if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "':' is expected.")) return false; switchBodyStmt.NextChar(); // skip ':' stxDefault.AddChild(new Block() { Location = new Context.LocationInfo() { FirstLine = word.AbsoluteLine, FirstPos = word.AbsoluteStartPos, LastLine = src.AbsoluteLine, LastPos = src.AbsolutePos } }); if (!Parse(stxDefault.Body, GetCaseBodyCode(ctx, switchBodyStmt))) return false; } break; default: if (!NotifyError(ctx, GetLocation(word.AbsoluteLine, word.AbsoluteStartPos, switchBodyStmt.AbsoluteLine, switchBodyStmt.AbsolutePos), ParsingErrorType.SyntaxError, "\"case\" is expected but get \"" + word.Text + "\".")) return false; break; } } // while stxSwitch.Body.RemoveChild(stxDefault); stxSwitch.Body.AddChild(stxDefault); stxSwitch.Location.LastLine = src.AbsoluteLine; stxSwitch.Location.LastPos = src.AbsolutePos; return true; }
表达式解析分为两步,第一步先生成Statement对象,再以此对象为基础进行解析。
第一步:
private bool ParseExpression(Context ctx, SourceCode src, Context.LocationInfo loc) { Statement stmtStx = new Statement() { Name = Context.GetAnonymousName("statement"), Location = loc }; if (!ParseExpression(ctx, src, ref stmtStx.TargetExpression)) return false; ctx.AddChild(stmtStx); stmtStx.Location.LastLine = src.AbsoluteLine; stmtStx.Location.LastPos = src.AbsolutePos; NotifyParsing(stmtStx); return true; }
第二步:
private bool ParseExpression(Context ctx, SourceCode src, ref Expression.ExpressionNode expTree) { bool res = true; while (!src.Eof && res) { src.SkipSpace(); switch (src.CurrentChar) { case ',': { src.NextChar(); // skip ',' Statement stxExp = new Statement(); if (ctx.Parent != null) ctx.Parent.AddChild(stxExp); else ctx.AddChild(stxExp); res = ParseExpression(ctx, src, ref stxExp.TargetExpression); } break; case ';': src.NextChar(); break; // End of statement case '=': res = ParseExpression_Equal(ctx, src, ref expTree); break; case '+': res = ParseExpression_Plus(ctx, src, ref expTree); break; case '-': res = ParseExpression_Minus(ctx, src, ref expTree); break; case '*': res = ParseExpression_Mul(ctx, src, ref expTree); break; case '/': res = ParseExpression_Div(ctx, src, ref expTree); break; case '%': res = ParseExpression_Mod(ctx, src, ref expTree); break; case '&': res = ParseExpression_And(ctx, src, ref expTree); break; case '|': res = ParseExpression_Or(ctx, src, ref expTree); break; case '^': res = ParseExpression_Xor(ctx, src, ref expTree); break; case '!': res = ParseExpression_Not(ctx, src, ref expTree); break; case '~': res = ParseExpression_BitwiseNot(ctx, src, ref expTree); break; case '<': res = ParseExpression_Less(ctx, src, ref expTree); break; case '>': res = ParseExpression_Greater(ctx, src, ref expTree); break; case '(': res = ParseExpression_Parentheses(ctx, src, ref expTree); break; case '\'': res = ParseExpression_CharValue(ctx, src, ref expTree); break; case '"': { // const string res = ParseExpression_ConstStringValue(ctx, src, ref expTree); //if (!FireParsingFailedEvent(ctx, src, ParsingErrorType.SyntaxError, "String is not supported.")) // return false; } break; default: { Expression.ExpressionNode lastNode = m_lastExpNode; if (SourceCode.IsDigit(src.CurrentChar)) { res = ParseExpression_NumberValue(ctx, src, ref expTree); } else if (SourceCode.IsLetter(src.CurrentChar)) { res = ParseExpression_Var(ctx, src, ref expTree); } else if (!NotifyError(ctx, src.Location, ParsingErrorType.SyntaxError, "Syntax error.")) return false; if (!ValidateOperator(ctx, src, lastNode)) return false; } break; } // switch } // while !Eof return res; } // func ParseExpression