/// <summary>
        /// 出错处理程序
        /// </summary>
        private void Error()
        {
            // 找到当前符号表栈顶元素对应的"式后字"
            // 将符号表栈顶元素出栈
            // 将"式后字"之前的所有非终结符号出栈

            ParseTreeNode symbolNode = this.symbolStack.Peek();

            this.targetTree.IsSuccess = false;

            // 如果是终结符号则直接出栈
            if (symbolNode.IsLeaf)
            {
                //symbolStack.Pop();
                PopSymbolStack();
                if (inputStack.Count > 0)
                {
                    inputStack.Pop();
                }
            }
            else
            {
                // 如果是非终结符号则找对应的follow集合
                switch (symbolNode.NSymbol)
                {
                case NEnum.program:
                    // $
                    ProcessFollowTerminal(TerminalType.END);
                    break;

                case NEnum.stmt_sequence:
                    // $ }
                    ProcessFollowTerminal(TerminalType.END, TerminalType.RBRACE);
                    break;

                case NEnum.statement:
                    // if while id read write int real } $
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.stmt_block:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.if_stmt:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.if_stmt_block:
                    // else
                    ProcessFollowTerminal(TerminalType.ELSE);
                    break;

                case NEnum.else_stmt_block:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.while_stmt:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.assign_stmt:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.read_stmt:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.write_stmt:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.declare_stmt:
                    // if while id read write int real } else
                    ProcessFollowTerminal(TerminalType.IF, TerminalType.WHILE, TerminalType.ID,
                                          TerminalType.READ, TerminalType.WRITE, TerminalType.INT, TerminalType.REAL,
                                          TerminalType.RBRACE, TerminalType.END);
                    break;

                case NEnum.variable:
                    // < > <> == ) ; ] * / + -
                    ProcessFollowTerminal(TerminalType.LESS, TerminalType.GREATER, TerminalType.EQUAL,
                                          TerminalType.RPARENT, TerminalType.SEMI, TerminalType.RBRACKET, TerminalType.MUL,
                                          TerminalType.DIV, TerminalType.PLUS, TerminalType.MINUS, TerminalType.NOTEQUAL);
                    break;

                case NEnum.exp:
                    // + - * / < > <> == ) ;
                    ProcessFollowTerminal(TerminalType.PLUS, TerminalType.MINUS, TerminalType.MUL,
                                          TerminalType.DIV, TerminalType.LESS, TerminalType.GREATER, TerminalType.EQUAL,
                                          TerminalType.NOTEQUAL, TerminalType.RPARENT, TerminalType.SEMI);
                    break;

                case NEnum.addtive_exp:
                    // + - * / < > <> == ) ;
                    ProcessFollowTerminal(TerminalType.PLUS, TerminalType.MINUS, TerminalType.MUL,
                                          TerminalType.DIV, TerminalType.LESS, TerminalType.GREATER, TerminalType.EQUAL,
                                          TerminalType.NOTEQUAL, TerminalType.RPARENT, TerminalType.SEMI);
                    break;

                case NEnum.term:
                    // + - * / < > <> == ) ;
                    ProcessFollowTerminal(TerminalType.PLUS, TerminalType.MINUS, TerminalType.MUL,
                                          TerminalType.DIV, TerminalType.LESS, TerminalType.GREATER, TerminalType.EQUAL,
                                          TerminalType.NOTEQUAL, TerminalType.RPARENT, TerminalType.SEMI);
                    break;

                case NEnum.factor:
                    // + - * / < > <> == ) ;
                    ProcessFollowTerminal(TerminalType.PLUS, TerminalType.MINUS, TerminalType.MUL,
                                          TerminalType.DIV, TerminalType.LESS, TerminalType.GREATER, TerminalType.EQUAL,
                                          TerminalType.NOTEQUAL, TerminalType.RPARENT, TerminalType.SEMI);
                    break;

                case NEnum.logical_op:
                    // ( intVal realVal id + -
                    ProcessFollowTerminal(TerminalType.LPARENT, TerminalType.INTVAL, TerminalType.REALVAL,
                                          TerminalType.ID, TerminalType.PLUS, TerminalType.MINUS);
                    break;

                case NEnum.add_op:
                    // ( intVal realVal id + -
                    ProcessFollowTerminal(TerminalType.LPARENT, TerminalType.INTVAL, TerminalType.REALVAL,
                                          TerminalType.ID, TerminalType.PLUS, TerminalType.MINUS);
                    break;

                case NEnum.mul_op:
                    // ( intVal realVal id + -
                    ProcessFollowTerminal(TerminalType.LPARENT, TerminalType.INTVAL, TerminalType.REALVAL,
                                          TerminalType.ID, TerminalType.PLUS, TerminalType.MINUS);
                    break;
                }
            }
        }
        /// <summary>
        /// 利用当前栈顶元素查找预测分析表并修改符号表
        /// 该函数无法处理标识符类型和表达式类型
        /// </summary>
        /// <param name="symbolNode">当前正在研究的符号表的栈顶元素</param>
        /// <returns>是否语法分析成功</returns>
        private bool LookUpTable(ParseTreeNode symbolNode,
                                 out List <ErrorInfo> errorInfos)
        {
            errorInfos = new List <ErrorInfo>();
            bool isSuccess = true;                   // 是否语法分析成功

            Token         token = inputStack.Peek(); // 输入串中的当前讨论的token
            ParseTreeNode treeNode;                  // 用于接收新建的语法树结点

            // 对于非终结符号,则参照预测分析表找到产生式
            // 在没有遇到exp或者variable的情况下,只会有一条产生式满足规则
            // 产生式列表
            List <ParsingTableItem> productions =
                this.parsingTable.GetItem(symbolNode.NSymbol, token.TokenType);

            if (productions == null || productions.Count == 0)
            {
                // TODO 语法分析错误处理
                isSuccess = false;
            }
            else
            {
                List <ParseTreeNode> production = productions[0].production;

                // 生成对应的树结点,并设置子树
                for (int i = 0; i < production.Count; i++)
                {
                    // 对于“空”终结符号,则不产生任何树结点
                    if (production[i].TSymbol != TerminalType.EMPTY)
                    {
                        treeNode = new ParseTreeNode(production[i].IsLeaf,
                                                     production[i].TSymbol, production[i].NSymbol);

                        symbolNode.Childs.Add(treeNode);
                    }
                }

                // 将产生式对应的(非)终结符号入栈, 入栈顺序与childs顺序相反
                for (int i = symbolNode.Childs.Count - 1; i >= 0; i--)
                {
                    // 对于“空”终结符号,则不push任何符号
                    // 对于“断点”,不push任何符号
                    if (symbolNode.Childs[i].TSymbol != TerminalType.EMPTY &&
                        symbolNode.Childs[i].TSymbol != TerminalType.BREAKPOINT)
                    {
                        symbolStack.Push(symbolNode.Childs[i]);
                    }
                }

                // 断点处理
                // 如果对应的token是断点所在行,则加入断点
                // 如果是stmtblock和stmtsequence均需要断点处理
                treeNode = new ParseTreeNode(false, TerminalType.DEFAULT,
                                             NEnum.statement);
                treeNode.Childs.Add(new ParseTreeNode(true, TerminalType.BREAKPOINT,
                                                      NEnum.DEFAULT));
                if (symbolNode.NSymbol == NEnum.stmt_sequence &&
                    production[0].TSymbol != TerminalType.EMPTY &&
                    this.bPLineNums.Contains(token.LineNum))
                {
                    // stmt-sequence
                    symbolNode.Childs.Insert(0, treeNode);
                }
                //if (symbolNode.NSymbol == NEnum.stmt_block &&
                //    production[0].TSymbol != TerminalType.EMPTY &&
                //    (this.bPLineNums.Contains(token.LineNum) ||
                //    this.bPLineNums.Contains(token.LineNum + 1)))
                //{
                //    // stmt-block
                //    symbolNode.Childs.Insert(1, treeNode);
                //}

                // 如果是Empty,则还应将符号栈栈顶元素出栈
                if (production[0].TSymbol == TerminalType.EMPTY)
                {
                    PopSymbolStack(true);
                }
            }

            return(isSuccess);
        }
        /// <summary>
        /// 利用词法分析的结果进行语法分析
        /// </summary>
        /// <param name="tokenResult">由词法分析得到的token结果</param>
        /// <param name="bpList">断点行号列表</param>
        /// <returns>语法分析树</returns>
        public ParseTree SyntacticAnalysis(TokenResult tokenResult,
                                           List <int> bpList)
        {
            #region 语法分析初始化

            // 初始化断点列表
            this.bPLineNums = bpList;

            this.targetTree.IsSuccess = true;                          // 表示语法分析是否成功
            List <ErrorInfo> totalErrorInfos = new List <ErrorInfo>(); // 总的报错信息

            // 将所有token读入栈
            for (int i = tokenResult.Tokens.Count - 1; i >= 0; i--)
            {
                if (tokenResult.Tokens[i].TokenType != TerminalType.NOTES)
                {
                    inputStack.Push(tokenResult.Tokens[i]);
                }
            }

            // 将结束符号放入符号栈中
            ParseTreeNode EndNode = new ParseTreeNode(true, TerminalType.END, NEnum.DEFAULT);
            symbolStack.Push(EndNode);

            // 将program放入符号栈
            symbolStack.Push(targetTree.Root);

            #endregion

            #region 语法分析主体程序
            // 每次从输入栈中读取一个符号并更新符号栈的值
            // 当没有读到$时进行循环,如果下一个是结束符号$则结束循环
            Token         token;      // 输入串中的当前讨论的token
            ParseTreeNode symbolNode; // 符号表中当前讨论的结点

            while (inputStack.Count > 0 && symbolStack.Count > 0)
            {
                token      = inputStack.Peek();
                symbolNode = symbolStack.Peek();

                // 遇到注释则跳过
                if (symbolNode.TSymbol == TerminalType.NOTES)
                {
                    continue;
                }

                #region 特殊非终结符号处理
                // 遇到标识符特殊考虑
                List <ErrorInfo> variableErrorInfos, expErrorInfos;
                if (symbolNode.NSymbol == NEnum.variable)
                {
                    this.VariableAnalyse(symbolNode, out variableErrorInfos);
                    totalErrorInfos.AddRange(variableErrorInfos);
                    continue;
                }

                // 遇到表达式特殊考虑
                if (symbolNode.NSymbol == NEnum.exp)
                {
                    this.ExpAnalyse(symbolNode, out expErrorInfos);
                    // 将exp出栈
                    PopSymbolStack();
                    totalErrorInfos.AddRange(expErrorInfos);
                    continue;
                }
                #endregion

                #region 查看M[U, a]表
                // 由于只有exp和标识符的情况会出现递归,所以其他非终结符号直接读取产生式即可
                List <ErrorInfo> NonErrorInfos = new List <ErrorInfo>();   // 在查找M[U,a]表时出现的错误
                if (symbolNode.IsLeaf)
                {
                    // 如果符号栈栈顶是终结符号
                    // 如果是结束符号
                    if (symbolNode.TSymbol == TerminalType.END)
                    {
                        if (token.TokenType == TerminalType.END)
                        {
                            // 语法分析结束,语法分析成功
                            symbolStack.Pop();
                            inputStack.Pop();
                            break;
                        }
                        else
                        {
                            // TODO 语法分析出错处理
                            ErrorEncapsulation("程序结尾存在多余字符串");
                            //isSuccess = false;
                        }
                    }

                    // 如果终结符号不是结束符号,则判断与输入表栈顶是否相同
                    if (symbolNode.TSymbol == token.TokenType)
                    {
                        // 将符号表和输入表栈顶元素出栈
                        // 如果符号栈栈顶元素是后一个元素子结点中的最后一个节点,则
                        // 应该将上一个结点也出栈
                        symbolNode.StringValue = token.StrValue;
                        symbolNode.LineNum     = token.LineNum;
                        PopSymbolStack();
                        inputStack.Pop();
                    }
                    else
                    {
                        // TODO 语法分析出错处理
                        ErrorEncapsulation($"缺少符号 '{T2String(symbolNode.TSymbol)}'");
                    }
                }
                else
                {
                    // 如果查找表失败则进行错误处理
                    if (!LookUpTable(symbolNode, out NonErrorInfos))
                    {
                        // TODO 出错处理
                        ErrorEncapsulation($"语法成分 '{N2String(symbolNode.NSymbol)}' 不能以" +
                                           $" '{T2String(token.TokenType)}' 符号开头");
                    }
                }
                #endregion
            }
            #endregion

            // 返回构建好的语法分析树
            //this.targetTree.IsSuccess = isSuccess;
            this.targetTree.ErrorInfos = this.targetTree.ErrorInfos.OrderBy(e => e.LineNum).ToList();

            return(this.targetTree);
        }
Пример #4
0
        /// <summary>
        /// 异步运行语义分析程序
        /// </summary>
        /// <param name="node"></param>
        public static void threadMethod(object node)
        {
            ParseTreeNode n = (ParseTreeNode)node;

            SentenceAnalysis.nodeAnalysis(n);
        }