📄 form1.cs
字号:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace test3
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Label label1;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox2 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(24, 40);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(256, 21);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "";
//
// button1
//
this.button1.Location = new System.Drawing.Point(296, 40);
this.button1.Name = "button1";
this.button1.TabIndex = 1;
this.button1.Text = "确定";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(24, 88);
this.textBox2.Multiline = true;
this.textBox2.Name = "textBox2";
this.textBox2.ReadOnly = true;
this.textBox2.Size = new System.Drawing.Size(352, 72);
this.textBox2.TabIndex = 2;
this.textBox2.Text = "";
//
// label1
//
this.label1.Location = new System.Drawing.Point(40, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(240, 16);
this.label1.TabIndex = 3;
this.label1.Text = "输入表达式以#结束";
//
// Form1
//
this.AutoScale = false;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(392, 174);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
this.MaximizeBox = false;
this.Name = "Form1";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
public char [,]O_Table =
{
// + - * / ( ) i #
{'>','>','<','<','<','>','<','>'},
{'>','>','<','<','<','>','<','>'},
{'>','>','>','>','<','>','<','>'},
{'>','>','>','>','<','>','<','>'},
{'<','<','<','<','<','=','<','-'},
{'>','>','>','>','-','>','-','>'},
{'>','>','>','>','-','>','-','>'},
{'<','<','<','<','<','-','<','='}
};//优先关系表:八个字符分别是 + - * / ( ) i # ,其中'-'表示出错
public struct SToken
{
public char ch; //存放字符:+-* /()i#E
public int No; //存放算符优先关系表中的序号
}
public SToken[] Token=new SToken[50] ; //单词序列,最后一个以“#”结束,
//各个字符用一数字表示其在表中的下标。
int TokenNumber = 0; //单词序列中包含的单词个数
int ipToken = 0; //进行“移进-规约”时的位置指示
//词法分析专用全局变量:
char ch; //存放取得的一个字符
public char[] Buffer;//=new char[BUFFER_SIZE]; //表达式缓冲区,以'\0'表示结束
int ipBuffer = 0; //表达式缓冲区当前位置序号
//运算符定义:
const int O_NUMBER= 8; //运算符个数,+-* /()i#
const int O_PLUS= 0; // 加 +
const int O_MINUS= 1; // 减 -
const int O_TIMES =2; // 乘 *
const int O_SLASH= 3; // 除 /
const int O_L_PAREN= 4;//左括号 (
const int O_R_PAREN= 5;//右括号 )
const int O_IDENT= 6; //标识符 i
const int O_NUL= 7; //语法界符 #
const bool TRUE =true;
const bool FALSE= false;
//错误信息:
string ErrMsg; //这个字符串存放 出错信息
//堆栈:由专门的函数操作(PopUp(),Push(),…)
const int STACK_MAX_SIZE = 50; //堆栈最大存储量
SToken[] Stack = new SToken[STACK_MAX_SIZE]; //堆栈
int ipStack = 0; //堆栈指针,指向栈顶(下一个空位置)
const int OG_NUMBER= 6; //文法个数
//char OG[OG_NUMBER][4] = {"E+E","E-E","E*E","E/E","(E)","i"}; //文法右部
//文法:
public char [,]OG = { {'E','+','E','\0'},
{'E','-','E','\0'},
{'E','*','E','\0'},
{'E','/','E','\0'},
{'(','E',')','\0'},
{'i','\0','\0','\0'}
};//文法右部
const int TOKEN_MAX_LENTH = 100; //最大的单词长度+1
private void button1_Click(object sender, System.EventArgs e)
{
char[] charRange =textBox1.Text.Trim().ToCharArray();
Buffer = charRange;
ipBuffer = 0;//做完一次后,表达式缓冲区当前位置序号返回开头。
if(ChangeToTokens()) //将表达式分割成单词序列
{
if(Judge()) //利用算符优先关系表判断表达式(单词序列)是否正确
OutPut(textBox1.Text,"正确!");
else
OutPut(textBox1.Text,ErrMsg); //输出错误信息
}
else //出错
{
OutPut(textBox1.Text,ErrMsg); //输出错误信息
}
}
bool Judge()
{
JudgeInit();
PushToken('#',O_NUL); //将“#”号置栈底
while(TRUE) //进行“移进-规约”操作
{
switch(MoveIn())
{
case 1: //需要规约
switch(GuiYue())//规约
{
case 1: //这一步规约成功
break;
case 2: //规约全部完成
return TRUE;
default: //出错
ErrMsg = "规约错误。";
return FALSE;
}
break;
case 2: //需要继续移进
break;
default: //出错
return FALSE;
}
}
}
//规约,并判断是否完成
//返回:-1出错,1这一步规约成功,2规约全部完成
int GuiYue()
{
int n0,n;
char r; //存优先关系
n = FindPriorOp(-1); //取得堆栈中第一个终结符
if(Peek(n).ch == '#') //出错或全部结束
{
if(IsOK())
return 2;
else
return -1;
}
while(TRUE)
{
n0 = n;
n = FindPriorOp(n0); //前一个终结符的堆栈位置
if(n - n0 > 2) //出错(多个非终结符相邻)
return -1;
r = O_Table[Peek(n).No,Peek(n0).No];
if(r == '<') //寻找结束
{
if(! GuiYueN(n - 1)) //规约(从前一个后的字符开始)规约失败
return -1;
else //规约成功,还要判断是否全部完成
{
if(IsOK())
return 2; //规约全部完成
else
return 1; //这一步规约成功
}
}
else if(r == '=') //继续向前找
{
continue;
}
else //出错(r为>或没有关系)
return -1;
}
}
//判断规约是否全部完成
//返回:TRUE全部完成;FALSE没有完成
bool IsOK()
{
if(Peek(0).ch == 'E'&& Peek(1).ch == '#' && Token[ipToken].ch == '#')
return TRUE;
else
return FALSE;
}
//返回:TRUE成功,FALSE失败
bool GuiYueN(int n) //将堆栈中0~n单词规约
{
int i,j;
bool k;
for(i=0;i<OG_NUMBER;i++) //将规约串和文法右部OG[][]每一个进行比较
{
for(j=n,k=FALSE;j>=0;j--)
{
if(OG[i,n-j] != Peek(j).ch)
{
k = TRUE; //TRUE表示规约串和文法右部不符,
break;
}
}
if(k) continue;
//k==FALSE表示规约串判断完成
if(OG[i,n+1]=='\0') //文法也判断完成,匹配成功
{
PopUp(n + 1); //弹出规约串
PushToken('E',O_IDENT); //压入左部“E”
return TRUE;
}
}
return FALSE;
}
//在堆栈中,从Begin开始,查找前一个终结符位置
//如果从开始找,让 Begin = -1
int FindPriorOp(int Begin)
{
int n;
n = Begin + 1;
while(Peek(n).ch == 'E')
{
n ++;
}
return n;
}
int MoveIn()
{
SToken s,t; //分别存堆栈顶单词和单词序列的第一个单词
char r; //存放优先关系
s = Peek(FindPriorOp(-1)); //取得堆栈中第一个终结符位置
t = Token[ipToken];
r = O_Table[s.No,t.No];
if(t.ch == '#') //单词结束,无法移进,需要规约
return 1;
else //单词没有结束,需判断是否可以移进
{
if(r == '<' || r == '=') //需要移进
{
Push(t);
ipToken ++;
return 2;
}
else if(r == '>') //不能移进,需要规约
return 1;
else //没有优先关系,出错
{
MakeErr("移进时出现两个没有优先关系的相邻单词。");
return -1;
}
}
}
//(利用算符优先关系表判断单词序列是否正确)判断前的初始化
//由于多个表达式需要依次判断,因此对每个表达式判断前都需要初始化
void JudgeInit()
{
ipStack = 0; //堆栈初始化(如果有专门的StackClear()函数则更好)
ipToken = 0; //指向首个单词
}
//窥视堆栈
//成功返回:返回单词
//不成功返回:NULL
SToken Peek(int n)
{
SToken Token;
if(n > 0 || n < ipStack)
Token = Stack[ipStack - n - 1];
else if(n < 0)
Token = Stack[ipStack - 1];
else
Token = Stack[0];
return Token;
}
void OutPut(string Formula, string Result)
{
textBox2.Text=Result;
}
//弹出堆栈
//不成功返回:FALSE
//成功返回:TRUE
bool PopUp(int n)
{
if(ipStack < 2) return FALSE; //只剩0个或1个
if(n > ipStack - 1) n = ipStack - 1;
ipStack -= n;
return TRUE;
}
//压栈(以字符形式)
//参数:ch是要压栈的字符(+-*/()i#E 之一),O_No运算符序号
//调用:Push()
void PushToken(char ch, int O_No)
{
SToken Token;//SToken是值类型的 不用new 关键字。
Token.ch = ch;
Token.No = O_No;
Push(Token);
}
//压栈
//参数:Token是要压栈的SToken结构体类型的单词
void Push(SToken Token)
{
Stack[ipStack ++] = Token;
}
bool ChangeToTokens()
{
TokenNumber = 0;
if(GetFirstChar() == '\0') return ! MakeErr("表达式为空。");//如果GetFirstChar()返回空,则表示表达示为空。
//ChangeToTokens()也到此为止。
while(TRUE) //对缓冲区进行循环读
{
if(ch <= 32 && ch > 0) GetFirstChar(); //滤去空格,如果为空,则再读入下一个字符。
switch(ch) //对单词的第一个进行判断,在下面一次处理整个单词
{
case '#':
Token[TokenNumber].ch = '#';
Token[TokenNumber].No = O_NUL;
return TRUE; //处理结束,因为#号为最后一个字符。
case '+':
Token[TokenNumber].ch = '+';
Token[TokenNumber].No = O_PLUS;
GetChar();
break;
case '-':
Token[TokenNumber].ch = '-';
Token[TokenNumber].No = O_MINUS;
GetChar();
break;
case '*':
Token[TokenNumber].ch = '*';
Token[TokenNumber].No = O_TIMES;
GetChar();
break;
case '/':
Token[TokenNumber].ch = '/';
Token[TokenNumber].No = O_SLASH;
GetChar();
break;
case '(':
Token[TokenNumber].ch = '(';
Token[TokenNumber].No = O_L_PAREN;
GetChar();
break;
case ')':
Token[TokenNumber].ch = ')';
Token[TokenNumber].No = O_R_PAREN;
GetChar();
break;
default:
if(ch >= '0' && ch <= '9') //整数
{
while(GetChar()>0)
{
if(ch < '0' || ch > '9') break;//不是数字时返回。如果是的话继续。
}
Token[TokenNumber].ch = 'i';//这里把所有的连在一起的数字用i表示。
Token[TokenNumber].No = O_IDENT;
}
else
{
return ! MakeErr("表达式中含有非法字符。");
}
break;
}
TokenNumber ++;
}
}
//从表达式缓冲区中取到下面第一个非空字符
//成功:返回字符;不成功:返回'\0'
char GetFirstChar()
{
while(GetChar() != '\0')//非空字符 时才返回这个字符。在这里去掉了所有的空格。
{ //如果为空则返回空。
if(ch>32) return ch;
}
return '\0';
}
//成功:返回字符;不成功:返回'\0'
char GetChar() //返回缓冲区中的字符直到#号结束。
{
if(Buffer.Length == 0)//表达示为空。返回'\0'。asc码这0。
return ch = '\0';
if((ch = Buffer[ipBuffer]) != '#')//如果ch等于#则不做ipBuffer ++
ipBuffer ++;
return ch;
}
//出错
bool MakeErr(string ErrMassage)
{
ErrMsg = ErrMassage;
return TRUE;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -