/// <summary> /// 登记符号表 /// </summary> /// <param name="name"></param> /// <returns></returns> private int Enter(Pascal o) { P_INDEX++; SymTable.Add(P_INDEX, o); return(P_INDEX); }
/// <summary> /// <语句表>→<语句> /// </summary> private void Act_1() { Pascal r1 = stack.Pop(); Pascal l = new Pascal(); l.Next = r1.Next; stack.Push(l); }
/// <summary> /// <算术表达式>→<项> /// </summary> private void Act_8() { Pascal r = stack.Pop(); Pascal l = new Pascal(); l.Text = r.Text; l.Num = r.Num; stack.Push(l); }
/// <summary> /// <关系表达式>→<算术表达式><关系符><算术表达式> /// </summary> private void Act_7() { Pascal r3 = stack.Pop(); Pascal r2 = stack.Pop(); Pascal r1 = stack.Pop(); Pascal l = new Pascal(); int ret = -1; int c = -1; switch (r2.Type) { case Type.LT: ret = (r1.Num < r3.Num) ? 1 : 0; c = 3; break; case Type.LE: ret = (r1.Num <= r3.Num) ? 1 : 0; c = 6; break; case Type.EQ: ret = (r1.Num == r3.Num) ? 1 : 0; c = 5; break; case Type.NE: ret = (r1.Num != r3.Num) ? 1 : 0; c = 8; break; case Type.GT: ret = (r1.Num > r3.Num) ? 1 : 0; c = 4; break; case Type.GE: ret = (r1.Num >= r3.Num) ? 1 : 0; c = 7; break; default: break; } l.Num = ret; //真假临时变量名字 l.Text = $"T{NewTemp(l.Num)}".ToCharArray(); int j = GEN(c, r1.TextToStr(r1.Text), r3.TextToStr(r3.Text), l.TextToStr(l.Text)); l.Next = j; stack.Push(l); }
/// <summary> /// <语句>→BEGIN<语句表>END /// </summary> private void Act_6() { stack.Pop(); Pascal r2 = stack.Pop(); stack.Pop(); Pascal l = new Pascal(); l.Next = r2.Next; stack.Push(l); }
/// <summary> /// <变量>→<标识符> L→k /// </summary> private void Act_15() { Pascal t = stack.Pop(); int findIndex = Entry(t.TextToStr(t.Text), t); Pascal r = (Pascal)SymTable[findIndex]; Pascal l = new Pascal(); l.Text = r.Text; l.Num = r.Num; stack.Push(l); }
/// <summary> /// 查、添符号表 /// </summary> /// <param name="name"></param> /// <returns></returns> private int Entry(string name, Pascal pascal) { int i = LookUp(name); if (i != 0) { return(i); } else { int index = Enter(pascal); SymTable.Add(name, index); return(index); } }
/// <summary> /// <项>→<项>*<因式> /// </summary> private void Act_11() { Pascal r3 = stack.Pop(); stack.Pop(); Pascal r1 = stack.Pop(); Pascal l = new Pascal(); l.Num = r1.Num * r3.Num; l.Text = $"T{NewTemp(l.Num)}".ToCharArray(); GEN(10, r1.TextToStr(r1.Text), r3.TextToStr(r3.Text), l.TextToStr(l.Text)); stack.Push(l); }
/// <summary> /// <语句>→IF<关系表达式>THEN<语句>ELSE<语句> /// </summary> private void Act_4() { Pascal r6 = stack.Pop(); Pascal r5 = stack.Pop(); Pascal r4 = stack.Pop(); Pascal r3 = stack.Pop(); Pascal r2 = stack.Pop(); Pascal r1 = stack.Pop(); for (int j = 0; j < SemtArr.Count; j++) { string[] o = SemtArr[j]; if (int.Parse(o[0]) == r3.TC) { SemtArr[j][1] = OPs[1]; SemtArr[j][2] = r2.TextToStr(r2.Text); SemtArr[j][3] = NULLStr; SemtArr[j][4] = (r3.TC + 2).ToString(); } if (int.Parse(o[0]) == r3.FC) { SemtArr[j][1] = OPs[2]; SemtArr[j][2] = r2.TextToStr(r2.Text); SemtArr[j][3] = NULLStr; SemtArr[j][4] = (r5.Next + 1).ToString(); } if (int.Parse(o[0]) == r5.Next) { SemtArr[j][1] = OPs[0]; SemtArr[j][2] = NULLStr; SemtArr[j][3] = NULLStr; SemtArr[j][4] = NXQ.ToString(); } } r3.TC = r4.Next; r3.FC = r6.Next; Pascal l = new Pascal(); stack.Push(l); }
/// <summary> /// <语句>→<变量>:=<算术表达式> /// </summary> private void Act_3() { Pascal r3 = stack.Pop(); stack.Pop(); Pascal r1 = stack.Pop(); Pascal l = new Pascal(); r1.Num = r3.Num; int index = Entry(r1.TextToStr(r1.Text), r1); r1 = (Pascal)SymTable[index]; r1.Num = r3.Num; int j = GEN(11, r3.TextToStr(r3.Text), NULLStr, r1.TextToStr(r1.Text)); l.Text = r1.Text; l.Num = r1.Num; l.Next = j; stack.Push(l); }
/// <summary> /// 初始化 /// </summary> private void Init() { //SymStack = new stack<Pascal>(); //状态栈初始化 StatusStack = new Stack <int>(); StatusStack.Push(0); //语义栈初始化 SemanticStack = new Stack <Pascal>(); Pascal stackTop = new Pascal(); stackTop.Num = -1; stackTop.Text[0] = '-'; SemanticStack.Push(stackTop); //语义分析初始化 SemanticAct = new Semantic(SemanticStack); foreach (Pascal pascal in SymList) { pascal.Id = (int)Type.TypeToId[pascal.Type]; } }
/// <summary> /// 语法分析开始 /// </summary> /// <returns></returns> public Hashtable Run() { //输出结果 Hashtable result = new Hashtable(); //接受 bool accept = true; //语法错误处 Pascal er = SymList[0];; int index = 0; int TopStat = StatusStack.Peek(); int InpSym = SymList[index].Id; while (ACTION[TopStat, InpSym] != Table.ACC) //acc { if (ACTION[TopStat, InpSym] == Table.ERR) //err { er = SymList[index]; accept = false; break; } else if (ACTION[TopStat, InpSym] > 0)//移进 { StatusStack.Push(ACTION[TopStat, InpSym]); int type = SymList[index].Type; if (type == Type.THEN || type == Type.DO) { SymList[index].TC = SemanticAct.NewLabel(); SymList[index].FC = SemanticAct.NewLabel(); } if (type == Type.ELSE) { SymList[index].Next = SemanticAct.NewLabel(); } SemanticStack.Push(SymList[index]); TopStat = StatusStack.Peek(); index++; InpSym = SymList[index].Id; } else if (ACTION[TopStat, InpSym] < 0)//归约 { int reduceIndex = ACTION[TopStat, InpSym]; //语义动作 Act(-reduceIndex); int sum = (int)Table.SumProdRight[ACTION[TopStat, InpSym]]; while (sum > 0) { StatusStack.Pop();//出栈 第i个产生式右部文法符号的个数 sum--; } TopStat = StatusStack.Peek(); int gotoPush = GOTO[TopStat, (int)Table.ProdIndex[reduceIndex]]; if (gotoPush == Table.ERR) { er = SymList[index]; accept = false; break; } StatusStack.Push(gotoPush); } TopStat = StatusStack.Peek(); } if (accept) { result.Add(Message.KEY, Message.SUCCESS); result.Add(Message.MSG, "语法分析ACCEPT!"); result.Add(Message.VALUE, SymList); } else { result.Add(Message.KEY, Message.FAILURE); result.Add(Message.MSG, $"语法 ERROR, 行:{er.X},列:{er.Y}"); } SemanticAct.Print(); SemanticAct.outFileStreamClose(); return(result); }
/// <summary> /// 根据类别码 输出词法分析报告 /// </summary> /// <param name="pascal">Pascal</param> /// <param name="outFileStream">输出流</param> private void OutputLog(Pascal pascal, FileStream outFileStream) { string str = null; if (info != null) { str = info; } switch (pascal.Type) { case Type.ID: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[{pascal.Type},{info}] {str}\n"; break; case Type.FINISH: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.GE: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.GT: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.IF: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.INT: info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{pascal.Num}] \n"; break; case Type.INTEGER: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.LE: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.LT: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.MUL: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.NE: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.SEM: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; //case Type.SUB: // info = pascal.TextToStr(pascal.Text); // info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; // break; case Type.THEN: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.VAR: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.WHILE: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.ADD: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.ASS: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.BEGIN: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.COL: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.COMMA: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; //case Type.DIV: // info = pascal.TextToStr(pascal.Text); // info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; // break; case Type.DO: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.ELSE: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.END: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.EQ: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Pascal.IR: info = $"({pascal.X},{pascal.Y}):\t{str} \n"; break; case Type.LP: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; case Type.RP: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t[ {pascal.Type } ,{info}] {str}\n"; break; default: info = pascal.TextToStr(pascal.Text); info = $"({pascal.X},{pascal.Y}):\t未识别字符类型 {info} ,{str} \n"; break; } //将字符串转换为字节数组 byte[] bytes = Encoding.UTF8.GetBytes(info); //向文件中写入字节数组 outFileStream.Position = outFileStream.Length;//指针移到最后 outFileStream.Write(bytes, 0, bytes.Length); info = null; }
/// <summary> /// 开始词法分析 /// </summary> /// <returns></returns> public Hashtable Run() { //输入字符数组 char[] codeChars; //临时Pascal词元数组 Pascal pascalWords; //Pascal词元数组 输出 List <Pascal> pascals = new List <Pascal>(); //输出结果 Hashtable result = new Hashtable(); //判断是否含有指定文件 if (!File.Exists(codeFilePath)) { //文件不存在! result.Add(Message.MSG, "文件不存在"); } //读入源码文件流 FileStream srcCodeFileStream = new FileStream(codeFilePath, FileMode.Open, FileAccess.Read); //定义存放文件信息的字节数组 byte[] bytes = new byte[srcCodeFileStream.Length]; //读取文件信息 srcCodeFileStream.Read(bytes, 0, bytes.Length); //将得到的字节型数组重写编码为字符型数组 codeChars = Encoding.UTF8.GetChars(bytes); //关闭流 srcCodeFileStream.Close(); //创建 输出词法分析结果流 FileStream outFileStream = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); //行列 int row = 1; int col = 1; int length = codeChars.Length; int index = 0; while (index < length) { pascalWords = new Pascal(); //注释标识 bool remark = false; //换行符 while (codeChars[index] == '\n') { row++; col = 1; index++; if (index == length) { index--; break; } } //空格 和 制表符 while (codeChars[index] == ' ' || codeChars[index] == '\t') { col++; index++; if (index == length) { index--; break; } } //字母 if (char.IsLetter(codeChars[index])) { //设定大写字母与数字组合是合法的,如果有小写字母或其他符号则是非法的 int k = 0; pascalWords.Text[k++] = codeChars[index]; pascalWords.X = row; pascalWords.Y = col; //小写字母开头 ISE错误 if (char.IsLower(codeChars[index]) || IsChinese(codeChars[index])) { pascalWords.Type = Pascal.ISE; info = "error:变量存在非法字符"; } index++;//下一个char col++; //字母或数字字符且不包含空格、逗号、分号的标点符号 while (index < length && char.IsLetterOrDigit(codeChars[index]) && codeChars[index] != ' ' && codeChars[index] != '\t' && codeChars[index] != ',' && codeChars[index] != ';') { pascalWords.Text[k++] = codeChars[index]; //符号和小写,如果之前已经发现了错误,默认保留之前的错误 if ((pascalWords.Type != Pascal.ISE) && (char.IsPunctuation(codeChars[index]) || char.IsLower(codeChars[index]) || IsChinese(codeChars[index]))) { pascalWords.Type = Pascal.ISE; info = "error:变量存在非法字符"; } index++; col++; if (index == length) { break; } } if (pascalWords.Type != Pascal.ISE) { //合法标识符成立 pascalWords.Type = Type.ID; //判断保留字 for (int m = 1; m <= 10; m++) { string text = new string(pascalWords.Text).Replace("\0", string.Empty); if (keywords[m - 1].Equals(text)) { //保留字 pascalWords.Type = 300 + m; break; } } } //标识符长度不合适 if (k > 8) { pascalWords.Type = Pascal.STL; info = "error:标识符长度不应大于8"; } } //数字 else if (char.IsDigit(codeChars[index])) { int sum; int k = 0; pascalWords = new Pascal(); pascalWords.Text[k++] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; //是否为字母或数字 while (char.IsLetterOrDigit(codeChars[index])) { pascalWords.Text[k++] = codeChars[index]; col++; if (char.IsLetter(codeChars[index])) { //此时判定该值不为数值 为变量 pascalWords.Type = Pascal.FDE; info = "error:变量首字母不应为数字"; } index++; if (index == length) { break; } } if (pascalWords.Type != Pascal.FDE) { sum = int.Parse(pascalWords.TextToStr(pascalWords.Text)); if (sum > 65535) { pascalWords.Type = Pascal.IO; info = "error:整数溢出 65535"; } else { pascalWords.Type = Type.INT; pascalWords.Num = sum; } } } //单分界符 else if (singleword.Contains(codeChars[index])) { switch (codeChars[index]) { case '+': pascalWords.Type = Type.ADD; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; //case '-': // pascalWords.Type = Type.SUB; // pascalWords.Text[0] = codeChars[index++]; // pascalWords.X = row; // pascalWords.Y = col++; // break; case '*': pascalWords.Type = Type.MUL; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; case ';': pascalWords.Type = Type.SEM; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; case ',': pascalWords.Type = Type.COMMA; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; case '=': pascalWords.Type = Type.EQ; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; case '(': pascalWords.Type = Type.LP; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; case ')': pascalWords.Type = Type.RP; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; break; default: Console.WriteLine("未知错误"); break; } } //双分界符首字符 else if (doubleword.Contains(codeChars[index])) { //下一个字符 char next; if (index + 1 < length) { next = codeChars[index + 1]; } else { next = '\0'; } switch (codeChars[index]) { case '>': if (next == '=') // >= { pascalWords.Text[0] = codeChars[index++]; pascalWords.Text[1] = next; pascalWords.Type = Type.GE; pascalWords.X = row; pascalWords.Y = col++; } else // > { pascalWords.Text[0] = codeChars[index]; pascalWords.Type = Type.GT; pascalWords.X = row; pascalWords.Y = col; } break; case '<': if (next == '=') // <= { pascalWords.Text[0] = codeChars[index++]; pascalWords.Text[1] = next; pascalWords.Type = Type.LE; pascalWords.X = row; pascalWords.Y = col++; } else if (next == '>') //<> { pascalWords.Text[0] = codeChars[index++]; pascalWords.Text[1] = next; pascalWords.Type = Type.NE; pascalWords.X = row; pascalWords.Y = col++; } else // < { pascalWords.Text[0] = codeChars[index]; pascalWords.Type = Type.LT; pascalWords.X = row; pascalWords.Y = col; } break; case ':': if (next == '=') // := { pascalWords.Text[0] = codeChars[index++]; pascalWords.Text[1] = next; pascalWords.Type = Type.ASS; pascalWords.X = row; pascalWords.Y = col++; } else // : { pascalWords.Text[0] = codeChars[index]; pascalWords.Type = Type.SEM; pascalWords.X = row; pascalWords.Y = col; } break; case '/': if (next == '/') // 单行注释 { remark = true; do { index++; col++; } while (index < length && codeChars[index] != '\n'); index--; col--; } else if (next == '*') //多行注释开始符 { remark = true; bool doneRemark = false; //多行注释成功标记 index += 2; // index->*.next col += 2; while (index < length) { if (codeChars[index] == '\n') { row++; index++; col = 1; continue; } else if (codeChars[index] == '*') { //多行注释结束识别 if (index + 1 < length) { next = codeChars[index + 1]; if (codeChars[index] == '*' && next == '/') //多行结束 { doneRemark = true; index++; col++; break; } } else { //*在最后一位 info = "error: 多行注释未完整 缺少‘/’"; pascalWords.Type = Pascal.IR; pascalWords.X = row; pascalWords.Y = col++; index++; remark = false; break; } } index++; col++; } if (!doneRemark && index == length && pascalWords.Type == Pascal.INIT) //无结尾 { info = "error: 多行注释未完整 缺少‘*/’"; pascalWords.Type = Pascal.IR; pascalWords.X = row; pascalWords.Y = col; remark = false; } } else // / { //pascalWords.Type = Type.DIV; pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; pascalWords.Type = Pascal.ISE; info = "error:未匹配字符"; } break; default: pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; pascalWords.Type = Pascal.ISE; info = "error:未匹配字符"; break; } index++; col++; } //结束符 # 处理 else if ('#' == codeChars[index]) { pascalWords.Type = Type.FINISH; pascalWords.Text[0] = codeChars[index]; pascalWords.X = row; pascalWords.Y = col; index = length; } else if (codeChars[index] == ' ' || codeChars[index] == '\t' || codeChars[index] == '\n') { continue; } //未匹配字符 else { pascalWords.Text[0] = codeChars[index++]; pascalWords.X = row; pascalWords.Y = col++; pascalWords.Type = Pascal.ISE; info = "error:未匹配字符"; } if (!remark) { //加入输出结果 pascals.Add(pascalWords); } if (pascalWords.Type != Pascal.INIT) { //输出文档 OutputLog(pascalWords, outFileStream); } else { pascalWords = null; } } //刷新缓冲区 outFileStream.Flush(); //关闭输出结果流 outFileStream.Close(); if (pascals.Count > 0) { result.Add(Message.KEY, Message.SUCCESS); result.Add(Message.MSG, "词法分析完成"); result.Add(Message.VALUE, pascals); } else { result.Add(Message.KEY, Message.FAILURE); result.Add(Message.MSG, "词法分析失败!请检查"); } return(result); }