C语言解释器-17 语法分析(2)

来源:互联网 发布:线切割割锥度编程 编辑:程序博客网 时间:2024/05/22 05:20

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