现在的位置: 首页 > 综合 > 正文

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

2012年12月14日 ⁄ 综合 ⁄ 共 8161字 ⁄ 字号 评论关闭

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

 

 

 

抱歉!评论已关闭.