/// <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); }
/// <summary> /// 异步运行语义分析程序 /// </summary> /// <param name="node"></param> public static void threadMethod(object node) { ParseTreeNode n = (ParseTreeNode)node; SentenceAnalysis.nodeAnalysis(n); }