【目的】 设计一个算符优先分析器,理解优先分析方法的原理。
【要求】 使用算符优先分析算法分析下面的文法:
E’ → #E#
E → E+T | T
T → T*F | F
F → P^F | P
P → (E) | i
其中i可以看作是一个终结符,无需作词法分析。具体要求如下:
1. 如果输入符号串为正确句子,显示分析步骤,包括分析栈中的内容、优先关系、输入符号串的变化情况;
2. 如果输入符号串不是正确句子,则指示出错位置。
【方法】 首先构造算符优先关系表,然后根据算符优先分析算法编写程序。
【实验环境和工具】 本实验使用的是C#。
说明:本程序输入的目标字符串要以#开头和结尾。
本程序的运行环境是visual studio 2005.net,选择的是控制台应用程序。
源程序代码:
/////文件【program.cs】
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//显示产生式的内容
Console.WriteLine("产生式为:=====================================================");
Class1 cs1 = new Class1();
cs1.generate = new Generate[9];
cs1.InitGenerate(cs1.generate);
cs1.Display(cs1.generate);
Console.WriteLine("");
Console.WriteLine();
cs1.DispTable();
//开始分析句子
Console.WriteLine();
Console.WriteLine("===============================================================");
Console.WriteLine("请输入目标句子(以#开头和结尾):");
Class1.strWhole = Console.ReadLine();
cs1.process();
Console.ReadLine();
}
}
}
/////[文件class1.cs]
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
public struct Generate //用结构体存储产生式
{
public char left;//左部
public string right;//右部
}
class Class1
{
public static string strWhole = "";//句子字符串
static char tempChar = ' ';//当前字符
static int p = 1;//剩余字符串的当前位置
static int top = 1;//栈顶
static int j = 1;
static char[] stack = new char[30];
public Generate[] generate;
char[] VT;//存储非终结符的数组
static char[] VN = new char[] { 'S', 'E', 'E', 'T', 'T', 'F', 'F', 'P', 'P' };
static char[,] priority = new char[7, 7];//存储算符优先关系的数组
public Class1()
{
stack[0] = ' ';
stack[1] = '#';
this.VT = new char[7] { '+', '*', '^', '(', ')', 'i', '#' };
}
//先初始化产生式并存入数组
public void InitGenerate(Generate[] generate)
{
generate[0].left = 'S';
generate[0].right = "#E#";
generate[1].left = 'E';
generate[1].right = "E+T";
generate[2].left = 'E';
generate[2].right = "T";
generate[3].left = 'T';
generate[3].right = "T*F";
generate[4].left = 'T';
generate[4].right = "F";
generate[5].left = 'F';
generate[5].right = "P^F";
generate[6].left = 'F';
generate[6].right = "P";
generate[7].left = 'P';
generate[7].right = "(E)";
generate[8].left = 'P';
generate[8].right = "i";
}
//将产生式进行显示
public void Display(Generate[] generate)
{
for (int i = 0; i < 9; i++)
{
Console.WriteLine("/t" + generate[i].left + "->" + generate[i].right);
}
}
public void DispTable()
{
//先将优先关系初始化为N
for (int i = 0; i < 7; i++)
for (int j = 0; j < 7; j++)
{
priority[i, j] = 'N';
}
//存储FIRSTVT集合
char[] FS = new char[] { '#' };
char[] FE = new char[] { '+', '*', '^', '(', 'i' };
char[] FT = new char[] { '*', '^', '(', 'i' };
char[] FF = new char[] { '^', '(', 'i' };
priority[6, 6] = '=';//# = #
priority[3, 4] = '=';//( = )
//#
for (int i = 0; i <= 6; i++)
{
for (int j = 0; j < 5; j++)
{
if (VT[i] == FE[j])
{
priority[3, i] = '<'; //( priority[6, i] = '<';
}
}
}
//+ for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
if (VT[i] == FT[j])
priority[0, i] = '<';
}
}
//* for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 3; j++)
{
if (VT[i] == FF[j])
{
priority[1, i] = '<';
priority[2, i] = '<';
}
}
}
//存储LASTVT集合
char[] LE = new char[] { '+', '*', '^', ')', 'i' };
char[] LT = new char[] { '*', '^', ')', 'i' };
char[] LP = new char[] { ')', 'i' };
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 5; j++)
{
if (VT[i] == LE[j])
{
priority[i, 6] = '>';//LASTVT(E)> #
priority[i, 0] = '>';//LASTVT(E)> +
priority[i, 4] = '>';//LASTVT(E)> ')'
}
}
}
//LASTVT(T)> *
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
if (VT[i] == LT[j])
priority[i, 1] = '>';
}
}
//LASTVT(P)> '^'
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 2; j++)
{
if (VT[i] == LP[j])
priority[i, 2] = '>';
}
}
//显示算府优先关系表
Console.WriteLine("算符优先关系表为:");
Console.WriteLine("/t+/t*/t^/t(/t)/ti/t#/t");
Console.WriteLine("----------------------------------------------------------");
for (int i = 0; i < 7; i++)
{
Console.Write(VT[i] + "/t");
for (int j = 0; j < 7; j++)
Console.Write(priority[i, j].ToString() + "/t");
Console.WriteLine();
}
}
public void process()
{
char result = ' ';
char Q = ' ';
string str="";
//确保以#开头和结尾
while (strWhole.Substring(0, 1) != "#" || strWhole.Substring(strWhole.Length - 1, 1) != "#")
{
Console.WriteLine("请重新输入,以#开头和结尾:");
strWhole = Console.ReadLine();
}
Console.WriteLine("栈 当前符号 剩余字符串 操作");
readNext();
Display();
while (true )
{
if (isMemVT(stack[top],this .VT ))
j = top;
else
j = top - 1;
result = CompareChar(stack[j], tempChar, this.VT);
if (result == '>')
{
Q = stack[j];
while (CompareChar(stack[j], Q, this.VT) != '<')
{
Q = stack[j];
if (isMemVT(stack[j - 1], this.VT))
j = j - 1;
else j = j - 2;
}
for (int i = j + 1; i <= top; i++)
{
str += stack[i];
}
Console.Write( "/t归约"+"/n");
top = j + 1;
stack[top] = 'N';
Display();
}
else if (result == '<')
{ Console.Write(" /t" + "移进" + "/n");
top = top + 1;
stack[top] = tempChar;
readNext();
Display();
}
else if (result == '=')
{
if (stack[j] == '#')
{
if (p == strWhole.Length - 1)
{
Console.WriteLine();
Console.WriteLine("分析成功!");
break;
}
else
{
Console.WriteLine("出错!");
break;
}
}
else
{
Console.Write("/t移进/n");
top = top + 1;
stack[top] = tempChar;
readNext();
Display();
}
}
else
{
Console .WriteLine ("出错!");
break;
}
}
}
static void Display()
{
for (int i = 1; i <= top; i++)
{
Console.Write(stack[i]);
}
Console.Write("/t/t" + tempChar.ToString()+"/t/t");
if (tempChar == '#') Console.Write("");
else
{
for (int i = p; i <= strWhole.Length - 1; i++)
{
Console.Write(strWhole[i]);
}
}
}
static bool isMemVT(char c, char[] VT)
{
bool r = false;
for (int i = 0; i <=VT.Length - 1; i++)
{
if (c == VT[i])
{
r = true;
break;
}
}
return r;
}
static void readNext()
{
tempChar = strWhole [p];
if (p <= strWhole.Length - 2)
p += 1;
else p = strWhole.Length - 1;
}
static char CompareChar(char c1, char c2, char[] VT)
{
int a = 0, b = 0;
for (int i = 0; i < 7; i++)
{
if (VT[i] == c1) a = i;
if (VT[i] == c2) b = i;
}
return priority[a, b];
}
public static void clear()
{
top = 1;
p = 1;
j = 1;
strWhole = "";
tempChar =' ';
strWhole="";
char []stack = new char[30];
}
}
}