江苏科技大学
编译原理实验报告
专业名称: 计算机科学与技术 __________
班 级: _______________
学 号: ______________
姓 名: _____________________
指导教师: ______________________
实验一 词法分析设计
通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用。
用VC++/VB/JAVA语言实现对C语言子集的源程序进行词法分析。通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示 ;同时进行标识符登记符号表的管理。
以下是实现词法分析设计的主要工作:
(1)从源程序文件中读入字符。
(2)统计行数和列数用于错误单词的定位。
(3)删除空格类字符,包括回车、制表符空格。
(4)按拼写单词,并用(内码,属性)二元式表示。(属性值——token的机内表示)
(5)如果发现错误则报告出错
(6)根据需要是否填写标识符表供以后各阶段使用。
单词的基本分类:
- 关键字:由程序语言定义的具有固定意义的标识符。也称为保留字例如 if、 for、while、printf ; 单词种别码为1。
- 标识符:用以表示各种名字,如变量名、数组名、函数名;
- 常数: 任何数值常数。如 125, 1,0.5,3.1416;
- 运算符:+、-、*、/;
- 关系运算符: <、<=、= 、>、>=、<>;
- 分界符: ;、,、(、)、[、];
1、主程序设计考虑:
- 程序的说明部分为各种表格和变量安排空间。
在具体实现时,将各类单词设计成结构和长度均相同的形式,较短的关键字后面补空。
k数组------关键字表,每个数组元素存放一个关键字(事先构造好关键字表)。
s 数组------存放分界符表(可事先构造好分界符表)。为了简单起见,分界符、算术运算符和关系运算符都放在s表中(编程时,应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。
id 和ci 数组分别存放标识符和常数。
instring 数组为输入源程序的单词缓存。
outtoken 记录为输出内部表示缓存。
还有一些为造表填表设置的变量。
- 主程序开始后,先以人工方式输入关键字,造k表;再输入分界符等造 p 表。
- 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。
例如,把每一单词设计成如下形式: (type,pointer)
其中type指明单词的种类,例如:Pointer指向本单词存放处的开始位置。
还有一些为造表填表设置的变量。
- 主程序开始后,先以人工方式输入关键字,造k表;再输入分界符等造 p 表。
- 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。
例如,把每一单词设计成如下形式: (type,pointer)
其中type指明单词的种类,例如:Pointer指向本单词存放处的开始位置。
词法分析设计流程图
2、词法分析过程考虑
- 根据输入单词的第一个字符(有时还需读第二个字符),
判断单词类,产生类号:以字符k表示关键字;id表示标识符;
ci表示常数;s 表示分界符。
- 对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组 id 中,将常数变为二进制形式存入数组中 ci 中,并记录其在表中的位置。
lexical 过程中嵌有两个小过程:一个名为 getchar,其功能为从 instring 中按顺序取出一个字符,并将其指针 pint 加 1 ;另一个名为 error,当出现错误时,调用这个过程,输出错误编号。
- 要求:所有识别出的单词都用两个字节的等长表示,称为内部码。第一个字节为 t ,第二个字节为 i 。 t 为单词的种类。关键字的 t=1;分界符的 t=2;算术运算符的 t=3;关系运算符的 t=4;无符号数的 t=5;标识符的 t=6。i 为该单词在各自表中的指针或内部码值。表 1 为关键字表;表 2 为分界符表;表 3 为算术运算符的 i 值;表 4 为关系运算符的 i 值。
取字符和统计字符行列位置子程序
1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、将标识符填写的相应符号表须提供给编译程序的以后各阶段使用。
3、根据测试数据进行测试。测试实例应包括以下三个部分:
- 全部合法的输入。
- 各种组合的非法输入。
- 由记号组成的句子。
4、词法分析程序设计要求输出形式:
例:输入VC++语言的实例程序:
If i=0 then n++;
a﹤= 3b %);
输出形式为:
单词 二元序列 类 型 位置(行,列)
(单词种别,单词属性)
for (1,for ) 关键字 (1,1)
i ( 6,i ) 标识符 (1,2)
= ( 4,= ) 关系运算符 (1,3)
0 ( 5,0 ) 常数 (1,4)
then ( 1,then) 关键字 (1,5)
n (6,n ) 标识符 (1,6)
++ Error Error (1,7)
; ( 2, ; ) 分界符 (1,8)
a (6,a ) 标识符 (2,1)
﹤= (4,<= ) 关系运算符 (2,2)
3b Error Error (2,4)
% Error Error (2,4)
) ( 2, ) ) 分界符 (2,5)
; ( 2, ; ) 分界符 (2,6)
1、根据流程图编写出各个模块的源程序代码上机调试。
2、 编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计的词法分析程序;直至能够得到完全满意的结果。
import java.io.IOException;
import java.io.InputStreamReader;
public class Q1{
private char ch;
private StringBuilder inString = new StringBuilder();
private StringBuilder outToken = new StringBuilder();
private int j;
private int row;
private int line;
public void startAnalyze() {
while(j < inString.length()){
getChar(); getBC();
if(isLetter()){
while(isLetter() || isDigit()){
concat(); getChar();
}
retract();
if(reserve()){
formatPrint(1);
}else{
// insertId();
formatPrint(6);
}
}else if(isDigit()){
while(isDigit()){
concat(); getChar();
}
if (isLetter()){
while (isLetter()){
concat(); getChar();
}
retract();
formatPrint(0);
continue;
}
retract();
// insertCount();
formatPrint(5);
}else{
if(isOther()){
concat();
getChar();
if(ch != '\0'){
if(isOther()){
concat();
}else {
retract();
}
}
formatPrint(getType());
}else{
concat();
formatPrint(0);
}
}
}
}
private int getType() {
int i = 0;
while (i < p.length){
if(p[i].equals(outToken.toString())){
break;
}
i++;
}
if(i < 6){
return 2;
}else if(i < 10){
return 3;
}else if(i < 16){
return 4;
}else{
boolean flag1 = false;
boolean flag2 = false;
for(int k = 0; k < 6; k++){
if(p[k].charAt(0) == outToken.toString().charAt(0)){
flag1 = true;
}
if(p[k].charAt(0) == outToken.toString().charAt(1)){
flag2 = true;
}
}
if(flag1 && flag2){
retract();
outToken.delete(1, 2);
return 2;
}
return 0;
}
}
public void getChar() {
if(j < inString.length()){
ch = inString.charAt(j++);
line++;
}else{
ch = '\0';
}
}
public void getBC(){
while(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'){
if(ch == '\n'){
row++;
line = 1;
}
getChar();
}
}
public boolean reserve(){
for(int i = 0; i < k.length; i++){
if(k[i].equals(outToken.toString())) return true;
}
return false;
}
public void concat() {
outToken.append(ch);
}
public void retract(){
// if(j <= inString.length()){
j--;
line--;
// }
}
public void insertId(){
}
public void insertCount(){
}
public boolean isDigit(){
return Character.isDigit(ch);
}
public boolean isLetter(){
return Character.isLetter(ch);
}
public boolean isOther(){
for(int i = 0; i < p.length; i++){
if(p[i].equals(String.valueOf(ch))){
return true;
}
}
return false;
}
public void formatPrint(int type){
String s = outToken.toString();
switch (type){
case 0:
System.out.printf("%s\tError\tError\t(%d, %d)\n", s, row, line - s.length());
break;
case 1:
System.out.printf("%s\t(1, %s)\t关键字\t(%d, %d)\n", s, s, row, line - s.length());
break;
case 2:
System.out.printf("%s\t(2, %s)\t分界符\t(%d, %d)\n", s, s, row, line - s.length());
break;
case 3:
System.out.printf("%s\t(3, %s)\t算数运算符\t(%d, %d)\n", s, s, row, line - s.length());
break;
case 4:
System.out.printf("%s\t(4, %s)\t关系运算符\t(%d, %d)\n", s, s, row, line - s.length());
break;
case 5:
System.out.printf("%s\t(5, %s)\t常数\t(%d, %d)\n", s, s, row, line - s.length());
break;
case 6:
System.out.printf("%s\t(6, %s)\t标识符\t(%d, %d)\n", s, s, row, line - s.length());
break;
default:
break;
}
outToken.delete(0, outToken.length());
}
// private HashSet<String> id = new HashSet<>();
// private HashSet<String> ci = new HashSet<>();
private String[] k;
private String[] p;
public Q1 () throws IOException {
k = new String[] {"do", "end", "for", "if", "printf", "scanf", "then", "while"};
p = new String[] {",", ";", "(", ")", "[", "]", "+", "-", "*", "/", "<", "<=", "=", ">", ">=", "<>"};
InputStreamReader reader = new InputStreamReader(Q1.class.getResourceAsStream("mimi.txt"));
for(int ch; (ch = reader.read()) != -1; ){
inString.append((char)ch);
}
row = 1; line = 1;
}
public static void main(String[] args) throws IOException {
try {
Q1 main = new Q1();
main.startAnalyze();
}catch(IOException e) {
e.printStackTrace();
}
}
1、词法分析器操作类
package 词法分析器;
七、运行结果
由于关键字表、关系运算符表、算术运算符表都是内部代码添加的,没有实现让用户自己添加的功能,本程序还只能分析*.c和*.java文件,而且没有区分大小写的功能。但由于代码比较灵活可以比较方便的修改,并添加想要的功能。
通过此次实验,我对词法分析器的运行步骤、组织结构有了更深层次的了解,熟练掌握了词法分析程序设计的原理和构造方法。
实验二 LL(1)分析法
通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。有利于提高学生的专业素质,为培养适应社会多方面需要的能力。
- 根据某一文法编制调试 LL ( 1 )分析程序,以便对任意输入的符号串进行分析。
- 构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。
- 分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。
三、 LL(1)分析法实验设计思想及算法
- 模块结构:
(1)定义部分:定义常量、变量、数据结构。
(2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);
(3)控制部分:从键盘输入一个表达式符号串;
(4)利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。
1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、如果遇到错误的表达式,应输出错误提示信息。
3、对下列文法,用LL(1)分析法对任意输入的符号串进行分析:
(1)E->TG
(2)G->+TG|—TG
(3)G->ε
(4)T->FS
(5)S->*FS|/FS
(6)S->ε
(7)F->(E)
(8)F->i
输出的格式如下:
1、根据流程图编写出各个模块的源程序代码上机调试。
2、 编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计的LL(1)分析程序;直至能够得到完全满意的结果。
public class LL1 {
private char[] strChar;// 输入串
private char[] stack = new char[1000];// 分析栈
private int top = 0;// 分析栈指针
private int strPointer = 0;// 输入串指针
private int length;// 输入串长度
private String[][] analysisTable = new String[6][9];// 分析表
private final char[] constChar = { 'i', '(', '+', '-', '*', '/', ')', '#' };// 常字符
private String[][] dataStrings = new String[1000][5];// 结果数据表
private String tempString = new String();// 临时字符串
private String result = new String();// 得出的结果字符串
private int dataRow = 0;// 数据表行数
/*
* 规则 i ( + - * / ) # E E->TG E->TG synch synch G G->+TG G->-TG G->ε G->ε T
* T->FS T->FS synch synch synch synch S S->ε S->ε S->*FS S->/FS S->ε S->ε F
* F->i F->(E) synch synch synch synch synch synch
*/
public LL1() {// 初始化各个参数
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 9; j++) {
analysisTable[i][j] = new String();
analysisTable[i][j] = " ";
}
}
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 5; j++) {
dataStrings[i][j] = new String();
dataStrings[i][j] = "";
}
}
analysisTable[0][1] = "i";
analysisTable[0][2] = "(";
analysisTable[0][3] = "+";
analysisTable[0][4] = "-";
analysisTable[0][5] = "*";
analysisTable[0][6] = "/";
analysisTable[0][7] = ")";
analysisTable[0][8] = "#";
analysisTable[1][0] = "E";
analysisTable[2][0] = "G";
analysisTable[3][0] = "T";
analysisTable[4][0] = "S";
analysisTable[5][0] = "F";
analysisTable[1][1] = "TG";
analysisTable[1][2] = "TG";
analysisTable[2][3] = "+TG";
analysisTable[2][4] = "-TG";
analysisTable[2][7] = "ε";
analysisTable[2][8] = "ε";
analysisTable[3][1] = "FS";
analysisTable[3][2] = "FS";
analysisTable[4][3] = "ε";
analysisTable[4][4] = "ε";
analysisTable[4][5] = "*FS";
analysisTable[4][6] = "/FS";
analysisTable[4][7] = "ε";
analysisTable[4][8] = "ε";
analysisTable[5][1] = "i";
analysisTable[5][2] = "(E)";
stack[top] = '#';
stack[++top] = 'E';
}
public boolean checkChar(char needCheck) {// 检查字符是否在字符表中
for (int i = 0; i < constChar.length; i++) {
if (needCheck == constChar[i]) {
return true;
}
}
return false;
}
public void printStack() {// 输出分析栈
this.tempString = new String();
for (int i = 0; i < top + 1; i++) {
this.tempString += stack[i];
System.out.print(stack[i]);
result += stack[i];
}
System.out.print("\t\t");
result += "\t\t";
}
public void printStr() {// 输出剩余输入串
this.tempString = new String();
for (int i = 0; i < strPointer; i++) {
System.out.print(" ");
result += " ";
}
for (int i = strPointer; i < length; i++) {
this.tempString += strChar[i];
System.out.print(strChar[i]);
result += strChar[i];
}
System.out.print("\t\t\t");
result += "\t\t\t";
}
public void analysis(String line) {// LL(1)分析
strChar = line.toCharArray();
length = strChar.length;
String analysisString = new String();
char ch = strChar[strPointer];
char topX;
int finish = 0, flag = 0;
int row = 0, column = 0;
System.out.print("步骤\t\t分析栈 \t\t剩余字符 \t\t所用产生式 \t\t动作\n");
result += "步骤\t\t分析栈 \t\t剩余字符 \t\t所用产生式 \t\t动作\r\n";
dataStrings[0][0] = dataRow++ + "";
System.out.print(dataRow + "\t\t");
result += dataRow + "\t\t";
printStack();
dataStrings[0][1] = tempString;
printStr();
dataStrings[0][2] = tempString;
dataStrings[0][4] = "初始化";
result += " \t\t初始化\r\n";
System.out.print("\n");
do {
topX = stack[top--];
dataStrings[dataRow][0] = dataRow + "";
System.out.print(dataRow + "\t\t");
result += dataRow + "\t\t";
for (int i = 0; i < 9; i++) {// 判断是否为非终结符
if (checkChar(topX)) {
flag = 1;
break;
}
}
if (flag == 1) {// 如果是终结符
if (topX == '#') {
finish = 1;
System.out.println("over");
result += "over\r\n";
break;
}
if (topX == ch) {
printStack();
dataStrings[dataRow][1] = tempString;
ch = strChar[++strPointer];
printStr();
dataStrings[dataRow][2] = tempString;
System.out.print("匹配\n");
dataStrings[dataRow][4] = "GETNEXT(I)";
result += " \t\tGETNEXT(I)\r\n";
flag = 0;
this.dataRow++;
} else {
printStack();
dataStrings[dataRow][1] = tempString;
printStr();
dataStrings[dataRow][2] = tempString;
System.out.print("错误\n");
result += " \t\t错误\r\n";
this.dataRow++;
break;
}
} else {
for (int i = 0; i < 6; i++) {
if (topX == analysisTable[i][0].charAt(0)) {
row = i;
break;
}
}
for (int i = 0; i < 9; i++) {
if (ch == analysisTable[0][i].charAt(0)) {
column = i;
break;
}
}
analysisString = analysisTable[row][column];
if (!analysisString.equals(" ")) {
if (!analysisString.equals("ε")) {
for (int i = analysisString.length() - 1; i >= 0; i--) {
stack[++top] = analysisString.charAt(i);
}
}
printStack();
dataStrings[dataRow][1] = tempString;
printStr();
dataStrings[dataRow][2] = tempString;
System.out.print(analysisTable[row][0] + "->"
+ analysisString + "\n");
dataStrings[dataRow][3] = analysisTable[row][0] + "->"
+ analysisString;
result += analysisTable[row][0] + "->" + analysisString;
if (!analysisString.equals("ε")) {
dataStrings[dataRow][4] = "POP,PUSH(" + analysisString
+ ")";
result += "\t\tPOP,PUSH(" + analysisString + ")\r\n";
} else {
dataStrings[dataRow][4] = "POP";
result += "\t\tPOP\r\n";
}
if (stack[top] == ' ') {
top--;
}
this.dataRow++;
} else {
printStack();
dataStrings[dataRow][1] = tempString;
printStr();
dataStrings[dataRow][2] = tempString;
System.out.print("出错\n");
result += " \t\t错误\r\n";
this.dataRow++;
break;
}
}
} while (finish == 0);
}
public String[][] getDataStrings() {
return dataStrings;
}
public void setDataStrings(String[][] dataStrings) {
this.dataStrings = dataStrings;
}
public int getDataRow() {
return dataRow;
}
public void setDataRow(int dataRow) {
this.dataRow = dataRow;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
package test2;
import java.io.BufferedReader;
public class LL1SWT {
protected Shell shell;
private Text text;
private Text text_1;
private Table table;
private MessageBox messageBox;
private File sourceFile = null;
private LL1_Opertion mOpertion;
private String Language = new String();
private String analysisString = new String();
private String result = new String();
/**
* Launch the application.
*
* @param args
*/
public static void main(String[] args) {
try {
LL1SWT window = new LL1SWT();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
protected void createContents() {
shell = new Shell();
shell.setSize(570, 565);
shell.setText("LL(1)\u5206\u6790\u5668");
Menu menu = new Menu(shell, SWT.BAR);
shell.setMenuBar(menu);
MenuItem menuItem = new MenuItem(menu, SWT.NONE);
menuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
try {
newTextTable();
} catch (Exception e2) {
e2.printStackTrace();
}
}
});
menuItem.setText("\u65B0\u5EFA");
MenuItem menuItem_1 = new MenuItem(menu, SWT.NONE);
menuItem_1.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openFile();
}
});
menuItem_1.setText("\u6253\u5F00");
MenuItem menuItem_3 = new MenuItem(menu, SWT.NONE);
menuItem_3.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
try {
analysis();
} catch (Exception e2) {
e2.printStackTrace();
}
}
});
menuItem_3.setText("\u5206\u6790");
MenuItem menuItem_2 = new MenuItem(menu, SWT.NONE);
menuItem_2.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
saveFile();
}
});
menuItem_2.setText("\u4FDD\u5B58");
MenuItem menuItem_4 = new MenuItem(menu, SWT.NONE);
menuItem_4.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
shell.dispose();
}
});
menuItem_4.setText("\u9000\u51FA");
ScrolledComposite scrolledComposite = new ScrolledComposite(shell,
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite.setBounds(10, 10, 367, 112);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
text = new Text(scrolledComposite, SWT.BORDER | SWT.V_SCROLL);
scrolledComposite.setContent(text);
scrolledComposite
.setMinSize(text.computeSize(SWT.DEFAULT, SWT.DEFAULT));
ScrolledComposite scrolledComposite_1 = new ScrolledComposite(shell,
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite_1.setBounds(383, 10, 161, 112);
scrolledComposite_1.setExpandHorizontal(true);
scrolledComposite_1.setExpandVertical(true);
text_1 = new Text(scrolledComposite_1, SWT.BORDER | SWT.V_SCROLL);
scrolledComposite_1.setContent(text_1);
scrolledComposite_1.setMinSize(text_1.computeSize(SWT.DEFAULT,
SWT.DEFAULT));
Language = "文法:\n"
+ "(1)E->TG\n(2)G->+TG|-TG\n(3)G->ε\n(4)T->FS\n(5)S->*FS|/FS\n"
+ "(6)S->ε\n(7)F->(E)\n(8)F->i";
text_1.setText(Language);
text_1.setEditable(false);
table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
table.setBounds(10, 128, 534, 368);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableColumn tblclmnNewColumn = new TableColumn(table, SWT.CENTER);
tblclmnNewColumn.setResizable(false);
tblclmnNewColumn.setWidth(66);
tblclmnNewColumn.setText("\u6B65\u9AA4");
TableColumn tableColumn = new TableColumn(table, SWT.NONE);
tableColumn.setWidth(114);
tableColumn.setText("\u5206\u6790\u6808");
TableColumn tblclmnNewColumn_1 = new TableColumn(table, SWT.NONE);
tblclmnNewColumn_1.setWidth(115);
tblclmnNewColumn_1.setText("\u5269\u4F59\u8F93\u5165\u4E32");
TableColumn tblclmnNewColumn_2 = new TableColumn(table, SWT.NONE);
tblclmnNewColumn_2.setWidth(115);
tblclmnNewColumn_2.setText("\u6240\u7528\u4EA7\u751F\u5F0F");
TableColumn tblclmnNewColumn_3 = new TableColumn(table, SWT.NONE);
tblclmnNewColumn_3.setWidth(115);
tblclmnNewColumn_3.setText("\u52A8\u4F5C");
}
public void openFile() {
FileDialog openFileDialog = new FileDialog(shell, SWT.OPEN);
openFileDialog.setText("选择需要分析的文件");
openFileDialog.setFilterExtensions(new String[] { "*.txt" });
openFileDialog.setFilterNames(new String[] { "txt文本文件(*.txt)" });
openFileDialog.setFilterPath("D:\\");
String selectedOpenFile = openFileDialog.open();
this.result = "";
if (selectedOpenFile != null) {
sourceFile = new File(selectedOpenFile);
try {
FileReader fileReader = new FileReader(sourceFile);
BufferedReader reader = new BufferedReader(fileReader);
StringBuffer stringBuffer = new StringBuffer();
String lineString = null;
while ((lineString = reader.readLine()) != null) {
stringBuffer.append(lineString);
stringBuffer.append("\n");
}
text.setText(stringBuffer.toString());
shell.setText("LL(1)分析 - " + openFileDialog.getFileName());
fileReader.close();
table.removeAll();
} catch (Exception e) {
e.printStackTrace();
}
} else {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("文件未载入!请重新打开需要分析的文件!");
messageBox.setText("提示");
messageBox.open();
}
}
public void analysis() {
mOpertion = new LL1_Opertion();
this.table.removeAll();
this.analysisString = text.getText();
boolean flag = false;
for (int i = 0; i < analysisString.length(); i++) {
if (mOpertion.checkChar(analysisString.charAt(0))) {
flag = true;
}
}
if (this.analysisString.equals("")) {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("请输入需要分析的字符串或打开需要分析的文件!");
messageBox.setText("提示");
messageBox.open();
} else if (flag) {
if (analysisString.charAt(analysisString.length() - 1) != '#') {
analysisString += "#";
}
this.result = "";
mOpertion.analysis(this.analysisString);
for (int i = 0; i < mOpertion.getDataRow(); i++) {
TableItem item = new TableItem(table, SWT.NULL);
for (int j = 0; j < 5; j++) {
item.setText(j, mOpertion.getDataStrings()[i][j]);
}
}
this.result = mOpertion.getResult();
} else {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("输入的字符串有错误!");
messageBox.setText("提示");
messageBox.open();
}
}
public void newTextTable() {
this.result = "";
this.text.setText("");
this.table.removeAll();
}
public void saveFile() {
if (result != "") {
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("Result.txt");
fileWriter.write(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
Runtime runtime = Runtime.getRuntime();
messageBox = new MessageBox(shell);
messageBox.setMessage("保存成功!");
messageBox.setText("提示");
fileWriter.flush();
fileWriter.close();
messageBox.open();
sourceFile = new File("Result.txt");
runtime.exec("rundll32 url.dll FileProtocolHandler "
+ sourceFile.getAbsolutePath());
} catch (Exception e2) {
e2.printStackTrace();
}
}
} else {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("未分析,保存失败!");
messageBox.setText("提示");
messageBox.open();
}
}
}
1.通过实验能利用正确的LL1文法分析表判断任意符号串是否属于该文法的句子;显示了具体分析过程;支持打开、新建、保存分析表;保存分析结果。
2.吸取了上次程序设计的经验教训,优化了代码整洁性,提高了程序设计效率,尽可能细化函数功能,便于移植、错误查找和修改
实验三 逆波兰表达式的产生及计算
非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
- 逆波兰式定义
将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。
- 产生逆波兰式的前提
中缀算术表达式
- 逆波兰式生成的设计思想及算法
(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
运用以上算法分析表达式(a+b*c)*d的过程如下:
当前符号 | 输入区 | 符号栈 | 输出区 |
( | a+b*c)*d | ||
a | +b*c)*d | ( | |
+ | *c)*d | ( | a |
b | c)*d | (+ | a |
* | )*d | (+ | ab |
c | *d | (+* | ab |
) | *d | (+* | abc |
) | *d | (+ | abc* |
) | d | ( | abc* |
* | abc*+ | ||
d | * | abc*+ | |
* | abc*+d | ||
abc*+d |
(1)构造一个栈,存放运算对象。
(2)读入一个用逆波兰式表示的简单算术表达式。
(3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对象,则将该字符入栈。若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。
(4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有字符都得到正确处理,我们便可以求出该简单算术表达式的值。
- 逆波兰式计算的设计思想及算法
1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、如果遇到错误的表达式,应输出错误提示信息。
3、程序输入/输出实例:
- 输入以#结束的中缀表达式(包括+ - */()数字#)。
例:(1)(a+b) (2)(a+b*c) (3) B+(-(A))*C
输出逆波兰表达式的格式如下:
(1) (a+b) ;→ab+)(
(2)(a+b*c)→abc*+)(
(3)B+(-A(A)) *C→BA)(-)(C*+
- 输入中缀表达式并计算结果:a* (b+c)+(-d)#;
输出逆波兰式:abc+*d@+
输入:a=3; b=1;c=2;d=5;
计算结果为:4
1、根据流程图编写出各个模块的源程序代码上机调试。
2、 编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计的逆波兰式的产生及计算程序;直至能够得到完全满意的结果。
流程图:
1、操作类
public class BY {
private char[] expChar = new char[100];// 表达式栈
private int expPointer = 0;// 表达式栈指针
private char[] ariStack = new char[100];// 运算符栈
private int top = 0;// 运算符栈指针
private char[] exitChar = new char[100];// 输出栈
private int exitPointer = 0;// 输出栈指针
private String[][] dataStrings = new String[1000][5];// 表格数据
private String tempString = new String();// 临时字符串
private String result = new String();// 结果字符串
private int row = 0;// 表格数据行
private String compValue = new String();// 计算值
private final char[] Arithmetic = { '+', '-', '*', '/', '(', ')', '#' };// 运算符
private final char[] Letter = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z' };// 字母表
private final char[] Digit = { '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0' };// 数字表
public BY() {
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 5; j++) {
dataStrings[i][j] = new String();
dataStrings[i][j] = "";
}
}
}
// 判断字符是否为字母
public boolean isLetter(char word) {
int N = 0;
while (N < Letter.length) {
if (word == Letter[N]) {
return true;
}
N++;
}
return false;
}
// 判断字符是否为数字
public boolean isDigit(char word) {
int N = 0;
while (N < Digit.length) {
if (word == Digit[N]) {
return true;
}
N++;
}
return false;
}
// 判断字符是否为算数运算符
public boolean isArithmetic(char word) {
int N = 0;
while (N < Arithmetic.length) {
if (word == Arithmetic[N]) {
return true;
}
N++;
}
return false;
}
// 输出剩余字符串
public void printExpChar() {
tempString = new String();
for (int i = expPointer; i < expChar.length; i++) {
tempString += expChar[i];
System.out.print(expChar[i]);
result += expChar[i];
}
System.out.print("\t\t");
result += "\t\t";
}
// 输出符号栈
public void printAriStack() {
tempString = new String();
for (int i = 0; i < top; i++) {
tempString += ariStack[i];
System.out.print(ariStack[i]);
result += ariStack[i];
}
System.out.print("\t\t");
result += "\t\t";
}
// 输出逆波兰式
public void printExitChar() {
tempString = new String();
for (int i = 0; i < exitPointer; i++) {
tempString += exitChar[i];
System.out.print(exitChar[i]);
result += exitChar[i];
}
System.out.print("\r\n");
result += "\r\n";
}
// 检查字符
public boolean checkString(String checkString) {
char ch;
for (int i = 0; i < checkString.length(); i++) {
ch = checkString.charAt(i);
if (isLetter(ch)) {
continue;
} else if (isDigit(ch)) {
continue;
} else if (isArithmetic(ch)) {
continue;
} else {
return false;
}
}
return true;
}
// 逆波兰分析
public void RPNAnalysis(String expression) {
expChar = expression.toCharArray();
char ch = expChar[expPointer++];
int temp = 0;
if (checkString(expression)) {
System.out.print("步骤\t当前符号\t输入区\t\t运算符号栈\t\t输出区\r\n");
result += "步骤\t当前符号\t输入区\t\t运算符号栈\t\t输出区\r\n";
while (ch != '#') {
if (isArithmetic(ch)) {
switch (ch) {
case '(':
ariStack[top++] = ch;
System.out.print(row + "\t" + ch + "\t");
result += row + "\t" + ch + "\t";
dataStrings[row][0] = row + "";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
break;
case ')':
while (ariStack[--top] != '(') {
exitChar[exitPointer++] = ariStack[top];
System.out.print(row + "\t" + ch + "\t");
result += row + "\t" + ch + "\t";
dataStrings[row][0] = row + "";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
}
System.out.print(row + "\t" + ch + "\t");
dataStrings[row][0] = row + "";
result += row + "\t" + ch + "\t";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
break;
case '+':
case '-':
temp = top - 1;
if (temp >= 0
&& (ariStack[temp] == '*' || ariStack[temp] == '/')) {
exitChar[exitPointer++] = ariStack[temp];
top--;
} else if (temp >= 0
&& (ariStack[temp] == '-' || ariStack[temp] == '+')
&& (expChar[expPointer + 1] != '*' || expChar[expPointer + 1] != '/')) {
exitChar[exitPointer++] = ariStack[temp];
top--;
}
while (top < 0 && ariStack[temp] != '(') {
exitChar[exitPointer++] = ariStack[temp];
top--;
}
ariStack[top++] = ch;
System.out.print(row + "\t" + ch + "\t");
result += row + "\t" + ch + "\t";
dataStrings[row][0] = row + "";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
break;
case '*':
case '/':
temp = top - 1;
if (temp >= 0
&& (ariStack[temp] == '*' || ariStack[temp] == '/')) {
exitChar[exitPointer++] = ariStack[temp];
top--;
}
ariStack[top++] = ch;
System.out.print(row + "\t" + ch + "\t");
result += row + "\t" + ch + "\t";
dataStrings[row][0] = row + "";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
break;
default:
break;
}
} else if (isLetter(ch) || isDigit(ch)) {
exitChar[exitPointer++] = ch;
System.out.print(row + "\t" + ch + "\t");
result += row + "\t" + ch + "\t";
dataStrings[row][0] = row + "";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
}
ch = expChar[expPointer++];
}
while (top != 0) {
temp = top - 1;
if (ariStack[temp] == '(') {
top--;
continue;
}
exitChar[exitPointer++] = ariStack[--top];
System.out.print(row + "\t" + ch + "\t");
result += row + "\t" + ch + "\t";
dataStrings[row][0] = row + "";
dataStrings[row][1] = String.valueOf(ch);
printExpChar();
dataStrings[row][2] = tempString;
printAriStack();
dataStrings[row][3] = tempString;
printExitChar();
dataStrings[row][4] = tempString;
row++;
}
}
}
// 计算值
public void compValue() {
int stack[] = new int[100];
exitChar[exitPointer++] = '#';
char ch;
int i = 0, top = 0;
ch = exitChar[i++];
while (ch != '#') {
switch (ch) {
case '+':
compValue += stack[top - 1] + " + " + stack[top];
stack[top - 1] = stack[top - 1] + stack[top];
compValue += " := " + stack[top - 1] + "\r\n";
top--;
break;
case '-':
compValue += stack[top - 1] + " - " + stack[top];
stack[top - 1] = stack[top - 1] - stack[top];
compValue += " := " + stack[top - 1] + "\r\n";
top--;
break;
case '*':
compValue += stack[top - 1] + " * " + stack[top];
stack[top - 1] = stack[top - 1] * stack[top];
compValue += " := " + stack[top - 1] + "\r\n";
top--;
break;
case '/':
compValue += stack[top - 1] + " / " + stack[top];
stack[top - 1] = stack[top - 1] / stack[top];
compValue += " := " + stack[top - 1] + "\r\n";
top--;
break;
default:
top++;
stack[top] = ch - '0';
break;
}
ch = exitChar[i++];
}
compValue += "结果:" + stack[top];
System.out.print(compValue);
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public String[][] getDataStrings() {
return dataStrings;
}
public void setDataStrings(String[][] dataStrings) {
this.dataStrings = dataStrings;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public char[] getExitChar() {
return exitChar;
}
public void setExitChar(char[] exitChar) {
this.exitChar = exitChar;
}
public String getCompValue() {
return compValue;
}
public void setCompValue(String compValue) {
this.compValue = compValue;
}
}
2、界面类
import java.io.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import com.swtdesigner.SWTResourceManager;
public class BYSWT {
protected Shell shell;
private Text text;
private Table varTable;
private Text resultText;
private Table resultTable;
private MessageBox messageBox;
private TableEditor editor;
private String result = "";
private File sourceFile = null;
private RPN_Operation mOperation;
private String analysisString;
String compValueString = new String();
private int varTableRow = 0;
private char[] varTableVar;
private char[] exitChar;
/**
* Launch the application.
*
* @param args
*/
public static void main(String[] args) {
try {
RPNSWT window = new RPNSWT();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
protected void createContents() {
shell = new Shell();
shell.setSize(500, 554);
shell.setText("逆波兰表达式的产生及计算");
Menu menu = new Menu(shell, SWT.BAR);
shell.setMenuBar(menu);
MenuItem menuItem = new MenuItem(menu, SWT.NONE);
menuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
newTextTable();
}
});
menuItem.setText("\u65B0\u5EFA");
MenuItem menuItem_1 = new MenuItem(menu, SWT.NONE);
menuItem_1.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openFile();
}
});
menuItem_1.setText("\u6253\u5F00");
MenuItem menuItem_2 = new MenuItem(menu, SWT.NONE);
menuItem_2.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
try {
analysis();
} catch (Exception e2) {
e2.printStackTrace();
}
}
});
menuItem_2.setText("\u5206\u6790");
MenuItem menuItem_6 = new MenuItem(menu, SWT.NONE);
menuItem_6.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
try {
compValue();
} catch (Exception e2) {
e2.printStackTrace();
}
}
});
menuItem_6.setText("\u8BA1\u7B97");
MenuItem menuItem_3 = new MenuItem(menu, SWT.NONE);
menuItem_3.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
saveFile();
}
});
menuItem_3.setText("\u4FDD\u5B58");
MenuItem menuItem_4 = new MenuItem(menu, SWT.NONE);
menuItem_4.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
shell.dispose();
}
});
menuItem_4.setText("\u9000\u51FA");
ScrolledComposite scrolledComposite = new ScrolledComposite(shell,
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite.setBounds(10, 10, 202, 119);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
text = new Text(scrolledComposite, SWT.BORDER);
scrolledComposite.setContent(text);
scrolledComposite
.setMinSize(text.computeSize(SWT.DEFAULT, SWT.DEFAULT));
varTable = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
varTable.setBounds(218, 10, 127, 119);
varTable.setHeaderVisible(true);
varTable.setLinesVisible(true);
editor = new TableEditor(varTable);
editor.horizontalAlignment = SWT.LEFT;
editor.grabHorizontal = true;
createEditorContents();
TableColumn tableColumn = new TableColumn(varTable, SWT.NONE);
tableColumn.setWidth(61);
tableColumn.setText("\u53D8\u91CF");
TableColumn tblclmnNewColumn = new TableColumn(varTable, SWT.NONE);
tblclmnNewColumn.setWidth(61);
tblclmnNewColumn.setText("\u503C");
ScrolledComposite scrolledComposite_1 = new ScrolledComposite(shell,
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite_1.setBounds(351, 10, 123, 119);
scrolledComposite_1.setExpandHorizontal(true);
scrolledComposite_1.setExpandVertical(true);
resultText = new Text(scrolledComposite_1, SWT.BORDER | SWT.H_SCROLL
| SWT.V_SCROLL | SWT.CANCEL);
resultText.setBackground(SWTResourceManager
.getColor(SWT.COLOR_LIST_BACKGROUND));
resultText.setEditable(false);
scrolledComposite_1.setContent(resultText);
scrolledComposite_1.setMinSize(resultText.computeSize(SWT.DEFAULT,
SWT.DEFAULT));
resultTable = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
resultTable.setBounds(10, 135, 464, 356);
resultTable.setHeaderVisible(true);
resultTable.setLinesVisible(true);
TableColumn tblclmnNewColumn_1 = new TableColumn(resultTable, SWT.NONE);
tblclmnNewColumn_1.setResizable(false);
tblclmnNewColumn_1.setWidth(59);
tblclmnNewColumn_1.setText("\u6B65\u9AA4");
TableColumn tblclmnNewColumn_2 = new TableColumn(resultTable, SWT.NONE);
tblclmnNewColumn_2.setWidth(100);
tblclmnNewColumn_2.setText("\u5F53\u524D\u7B26\u53F7");
TableColumn tblclmnNewColumn_3 = new TableColumn(resultTable, SWT.NONE);
tblclmnNewColumn_3.setWidth(100);
tblclmnNewColumn_3.setText("\u8F93\u5165\u533A");
TableColumn tblclmnNewColumn_4 = new TableColumn(resultTable, SWT.NONE);
tblclmnNewColumn_4.setWidth(100);
tblclmnNewColumn_4.setText("\u8FD0\u7B97\u7B26\u53F7\u6808");
TableColumn tblclmnNewColumn_5 = new TableColumn(resultTable, SWT.NONE);
tblclmnNewColumn_5.setWidth(100);
tblclmnNewColumn_5.setText("\u8F93\u51FA\u533A");
}
public void openFile() {
FileDialog openFileDialog = new FileDialog(shell, SWT.OPEN);
openFileDialog.setText("选择需要分析的文件");
openFileDialog.setFilterExtensions(new String[] { "*.txt" });
openFileDialog.setFilterNames(new String[] { "txt文本文件(*.txt)" });
openFileDialog.setFilterPath("D:\\");
String selectedOpenFile = openFileDialog.open();
this.result = "";
if (selectedOpenFile != null) {
sourceFile = new File(selectedOpenFile);
try {
FileReader fileReader = new FileReader(sourceFile);
BufferedReader reader = new BufferedReader(fileReader);
StringBuffer stringBuffer = new StringBuffer();
String lineString = null;
while ((lineString = reader.readLine()) != null) {
stringBuffer.append(lineString);
stringBuffer.append("\n");
}
text.setText(stringBuffer.toString());
shell.setText("逆波兰表达式分析器 - " + openFileDialog.getFileName());
fileReader.close();
varTable.removeAll();
resultTable.removeAll();
} catch (Exception e) {
e.printStackTrace();
}
} else {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("文件未载入!请重新打开需要分析的文件!");
messageBox.setText("提示");
messageBox.open();
}
}
public void newTextTable() {
this.result = "";
this.text.setText("");
this.resultText.setText("");
this.varTable.removeAll();
this.resultTable.removeAll();
}
public void saveFile() {
if (result != "") {
result += "\r\n" + compValueString;
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("Result.txt");
fileWriter.write(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
Runtime runtime = Runtime.getRuntime();
messageBox = new MessageBox(shell);
messageBox.setMessage("保存成功!");
messageBox.setText("提示");
fileWriter.flush();
fileWriter.close();
messageBox.open();
sourceFile = new File("Result.txt");
runtime.exec("rundll32 url.dll FileProtocolHandler "
+ sourceFile.getAbsolutePath());
} catch (Exception e2) {
e2.printStackTrace();
}
}
} else {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("未分析,保存失败!");
messageBox.setText("提示");
messageBox.open();
}
}
public void analysis() {
mOperation = new RPN_Operation();
this.resultTable.removeAll();
this.varTable.removeAll();
this.resultText.setText("");
this.analysisString = text.getText();
this.result = "";
boolean flag = false;
if (mOperation.checkString(this.analysisString)) {
flag = true;
}
if (this.analysisString.equals("")) {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("请输入需要分析的字符串或打开需要分析的文件!");
messageBox.setText("提示");
messageBox.open();
} else if (flag) {
if (analysisString.charAt(analysisString.length() - 1) != '#') {
analysisString += "#";
}
this.result = "";
mOperation.RPNAnalysis(this.analysisString);
for (int i = 0; i < mOperation.getRow(); i++) {
TableItem item = new TableItem(resultTable, SWT.NULL);
for (int j = 0; j < 5; j++) {
item.setText(j, mOperation.getDataStrings()[i][j]);
}
}
this.result = mOperation.getResult();
showVariable();
} else {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("输入的字符串有错误!");
messageBox.setText("提示");
messageBox.open();
}
}
public void showVariable() {
for (int i = 0; i < analysisString.length(); i++) {
if (mOperation.isLetter(analysisString.charAt(i))
|| mOperation.isDigit(analysisString.charAt(i))) {
varTableRow++;
}
}
varTableVar = new char[varTableRow];
varTableRow = 0;
for (int i = 0; i < analysisString.length(); i++) {
if (mOperation.isLetter(analysisString.charAt(i))
|| mOperation.isDigit(analysisString.charAt(i))) {
varTableVar[varTableRow] = analysisString.charAt(i);
varTableRow++;
}
}
boolean flag = true;
for (int i = 0; i < varTableRow; i++) {
for (int j = 0; j < varTable.getItems().length; j++) {
if (varTableVar[i] == varTable.getItems()[j].getText()
.charAt(0)) {
flag = false;
}
}
if (flag) {
TableItem item = new TableItem(varTable, SWT.NULL);
item.setText(0, String.valueOf(varTableVar[i]));
if (mOperation.isDigit(varTableVar[i])) {
item.setText(1, String.valueOf(varTableVar[i]));
} else {
item.setText(1, "");
}
}
flag = true;
}
}
public void createEditorContents() {
varTable.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent event) {
Control old = editor.getEditor();
if (old != null) {
old.dispose();
}
Point point = new Point(event.x, event.y);
final TableItem item = varTable.getItem(point);
if (item != null) {
int column = -1;
for (int i = 1, n = varTable.getColumnCount(); i < n; i++) {
Rectangle rectangle = item.getBounds(i);
if (rectangle.contains(point)) {
column = i;
break;
}
}
if (column >= 0) {
final Text text = new Text(varTable, SWT.NONE);
text.setText(item.getText(column));
text.selectAll();
text.setFocus();
editor.setEditor(text, item, column);
final int col = column;
text.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent arg0) {
item.setText(col, text.getText());
}
});
}
}
}
});
}
public char setValue(char var) {
for (int i = 0; i < varTable.getItems().length; i++) {
if (var == varTable.getItems()[i].getText().charAt(0)) {
return varTable.getItems()[i].getText(1).charAt(0);
}
}
return var;
}
public void compValue() {
if (result == "") {
messageBox = new MessageBox(shell, SWT.ICON_WARNING);
messageBox.setMessage("计算失败!请先分析!");
messageBox.setText("提示");
messageBox.open();
} else {
exitChar = new char[mOperation.getExitChar().length];
exitChar = mOperation.getExitChar();
for (int i = 0; i < exitChar.length; i++) {
exitChar[i] = setValue(exitChar[i]);
}
mOperation.setExitChar(exitChar);
mOperation.compValue();
compValueString = mOperation.getCompValue();
System.out.print(compValueString);
resultText.setText(compValueString);
}
}
}
通过本实验,我再次熟悉了逆波兰表达式的生成过程与计算过程,熟练的掌握了其程序的算法,以及数据结构。掌握逆波兰表达式程序设计的原理和构造方法,训练了我掌握开发应用程序的基本方法。
实验四 LR(1)分析法
构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
对下列文法,用LR(1)分析法对任意输入的符号串进行分析:
(1)E- E+T
(2)E- E—T
(3)T- T*F
(4)T- T/F
(5)F- (E)
(6)F- i
三、LR(1)分析法实验设计思想及算法
(1)总控程序,也可以称为驱动程序。对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
- LR分析器由三个部分组成:
- 其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。
- ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。动作有四种可能:
(1)移进:
action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。
(2)归约:
action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A- B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:
当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。
(4)报错:
当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。
1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、如果遇到错误的表达式,应输出错误提示信息。
3、程序输入/输出实例:
输入一以#结束的符号串(包括+—*/()i#):在此位置输入符号串
输出过程如下:
步骤 状态栈 符号栈 剩余输入串 动 作
1 0 # i+i*i# 移进
i+i*i的LR分析过程 | ||||
步骤 | 状态栈 | 符号栈 | 输入串 | 动作说明 |
1 | 0 | # | i+i*i# | ACTION[0,i]=S5,状态5入栈 |
2 | 05 | #i | +i*i# | r6: F→i归约,GOTO(0,F)=3入栈 |
3 | 03 | #F | +i*i# | r4: T→F归约,GOTO(0,T)=3入栈 |
4 | 02 | #T | +i*i# | r2: E→T归约,GOTO(0,E)=1入栈 |
5 | 01 | #E | +i*i# | ACTION[1,+]=S6,状态6入栈 |
6 | 016 | #E+ | i*i# | ACTION[6,i]=S5,状态5入栈 |
7 | 0165 | #E+i | *i# | r6: F→i归约,GOTO(6,F)=3入栈 |
8 | 0163 | #E+F | *i# | r4: T→F归约,GOTO(6,T)=9入栈 |
9 | 0169 | #E+T | *i# | ACTION[9,*]=S7,状态7入栈 |
10 | 01697 | #E+T* | i# | ACTION[7,i]=S5,状态5入栈 |
11 | 016975 | #E+T*i | # | r6:F→i归约,GOTO(7,F)=10入栈 |
12 | 0169710 | #E+T*F | # | r3: T→T*F归约,GOTO(6,T)=9入栈 |
13 | 0169 | #E+T | # | r1:E→E+T,GOTO(0,E)=1入栈 |
14 | 01 | #E | # | Acc:分析成功 |
4、输入符号串为非法符号串(或者为合法符号串)
算术表达式文法的LR分析表 | |||||||||
状 态 | ACTION | GOTO | |||||||
i | + | * | ( | ) | # | E | T | F | |
0 | S5 | S4 | 1 | 2 | 3 | ||||
1 | S6 | acc | |||||||
2 | r2 | S7 | r2 | r2 | |||||
3 | r4 | r4 | r4 | r4 | |||||
4 | S5 | S4 | 8 | 2 | 3 | ||||
5 | r6 | r6 | r6 | r6 | |||||
6 | S5 | S4 | 9 | 3 | |||||
7 | S5 | S4 | 10 | ||||||
8 | S6 | S11 | |||||||
9 | r1 | S7 | r1 | r1 | |||||
10 | r3 | r3 | r3 | r3 | |||||
11 | r5 | r5 | r5 | r5 |
1、根据流程图编写出各个模块的源程序代码上机调试。
2、编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计的LR(1)语法分析程序;直至能够得到完全满意的结果。
#include<iostream>
#include<stack>
#include<string>
using namespace std;
string action[12][6]={
"S5","0","0","S4","0","0", //ACTION表
"0","S6","0","0","0","acc",
"0","r2","S7","0","r2","r2",
"0","r4","r4","0","r4","r4",
"S5","0","0","S4","0","0",
"0","r6","r6","0","r6","r6",
"S5","0","0","S4","0","0",
"S5","0","0","S4","0","0",
"0","S6","0","0","S11","0",
"0","r1","S7","0","r1","r1",
"0","r3","r3","0","r3","r3",
"0","r5","r5","0","r5","r5"};
int gotoarr[12][3]={1,2,3, //GOTO表
0,0,0,
0,0,0,
0,0,0,
8,2,3,
0,0,0,
0,9,3,
0,0,10,
0,0,0,
0,0,0,
0,0,0,
0,0,0};
char vt[6]={'i','+','*','(',')','#'}; //存放终结符
char vn[3]={'E','T','F'}; //存放非终结符
string Production[6]={"E->E+T","E->T","T->T*F","T->F","F->(E)","F->i"};//产生式集合
int count=0;//记录当前进行处理的输入字符串字符位置
int line=1;//记录处理的步骤数
bool flag=false;
int StatusNumber=1;//栈中状态数
string stacktd="#";//记录符号栈中内容
int Status[50]={0};//记录状态栈
stack <char> Stack;//创建一个符号栈
stack <int> status;//创建一个状态栈
void Judge(int &i,int j,char arr[],char ch,string s){//判断输入串是否由文法终结符组成
flag=false;
for(int l=0;l<j;l++)
{
if(ch==arr[l])
{
flag=true;
i=l;
break;
}
}
if(flag==false)
{
cout<<"\tError"<<endl;
count=s.size();
}
}
void Outputstatus()
{
//输出状态集
for(int i=0;i<StatusNumber;i++)
cout<<Status[i];
}
void Outputstring(string s)
{
//输出未处理的字符串
for(int i=count;i<s.size();i++)
cout<<s.at(i);
}
void Output(string s)
{
//输出步骤、状态集、符号集、输入串
cout<<line<<"\t";
Outputstatus();
cout<<"\t"<<stacktd<<"\t";
Outputstring(s);
cout<<"\t\t";
line++;
}
void Shift(int i,string s)
{//移进函数S
Output(s);
cout<<"ACTION["<<status.top()<<","<<s.at(count)<<"]=S"<<i<<",状态"<<i<<"入栈"<<endl;
status.push(i);//将状态i压进状态栈
Status[StatusNumber]=i;//Status记录状态栈的内容
Stack.push(s.at(count));//将当前面临的输入串符号压进符号栈
stacktd=stacktd+s.at(count);//stacktd记录符号栈的内容
count++;//当前面临的输入串字符往后移一位
StatusNumber++;//状态数加一
}
void Goto(stack <int> st1,stack <char> st2,string s)
{//GoTo语句
int j=-1;
int ch1=st1.top();
char ch2=st2.top();
Judge(j,3,vn,ch2,s);//求得ch2在非终结符表中的位置
if(gotoarr[ch1][j]==0)
{
cout<<"\tError"<<endl;
count=s.size();
}
else
{
status.push(gotoarr[ch1][j]);//新状态进栈
Status[StatusNumber]=gotoarr[ch1][j];
StatusNumber++;
}
}
void Reduction(int i,string s)
{//归约函数R
Output(s);
cout<<"r"<<i<<":"<<Production[i-1]<<"归约,GoTo(";
int N=Production[i-1].length()-3;
for(int j=0;j<N;j++)
{//消除要归约的状态及符号
status.pop();
Stack.pop();
StatusNumber--;
stacktd.erase(stacktd.length()-1);
}
cout<<status.top()<<","<<Production[i-1].at(0)<<")=";
Stack.push(Production[i-1].at(0));//符号进栈
stacktd=stacktd+Stack.top();
Goto(status,Stack,s);
cout<<status.top()<<"入栈"<<endl;
Status[StatusNumber]=status.top();
}
void Analyse(string s)
{//具体分析函数
Stack.push('#');//初始化
status.push(0);
s=s+"#";
int t=-1;//记录ch在数组vt的位置
while(count<s.size())
{
int i=status.top();
char ch=s.at(count);
Judge(t,6,vt,ch,s);
if(flag==true)
{
if(action[i][t]!="acc"&&action[i][t]!="0")
{
if(action[i][t].at(0)=='S')
{
action[i][t].erase(0,1); //删除action[i][t]的首字母S
Shift(atoi(action[i][t].c_str()),s);//atoi(action[i][t].c_str()),将action[i][t]转换为整型
action[i][t].insert(0,"S");//将S添加回action[i][t]
}
else if(action[i][t].at(0)=='r'){
action[i][t].erase(0,1);//删除action[i][t]的首字母r
Reduction(atoi(action[i][t].c_str()),s);//atoi(action[i][t].c_str()),将action[i][t]转换为整型
action[i][t].insert(0,"r");//将r添加回action[i][t]
}
}
else if(action[i][t]=="0")
{
cout<<"\tError"<<endl;
break;
}
else if(action[i][t]=="acc")
{
Output(s);
cout<<"acc"<<"\t分析成功"<<endl;
break;
}
}
else if(flag==false)
break;
}
}
int main()
{
string s;
cout<<"************************LR(1)分析*************************"<<endl;
cout<<"本分析文法产生式为"<<endl;
for(int j=0;j<6;j++)
cout<<Production[j]<<endl;
cout<<"************************LR(1)分析*************************"<<endl;
char T;
do
{
cout<<"输入字符串"<<endl;
cin>>s;//输入要分析的字符串
cout<<"************************现进行如下分析 *************************"<<endl;
cout<<"步骤"<<"\t"<<"状态栈"<<"\t"<<"符号栈"<<"\t"<<"剩余输入串"<<"\t"<<"动作说明"<<endl;
Analyse(s);
count=0;//记录当前进行处理的输入字符串字符位置
line=1;//记录处理的步骤数
stacktd="#";
StatusNumber=1;
while(!Stack.empty())
{
Stack.pop();
}
while(!status.empty())
{
status.pop();
}
cout<<"是否继续分析,Y或y继续"<<endl;
cin>>T;
}
while(T=='y'||T=='Y');
return 0;
}
经过这个实验的练习,通过对程序的分析,让我进一步了解LR(1)算法的思想以及它的进一步程序实现。LR(0)构造的DFA,但是由LR(0)的DFA来构造分析表往往是不可行的,也就是说很少有语言是LR(0)的。如果LR(0)的冲突可以根据当前输入的字符来解决,则构造的分析表为SLR分析表,SLR分析表跟LR(0)的dfa是相同的。LR(1)构造的DFA考虑当前输入的字符,所以构造的DFA中存在的冲突比较少,也就是说它接受的语言就比较多。构造分析表时,不用额外的约束,因为它在构造dfa时就已经考虑了当前的输入字符。
通过练习我也感到理论仅留在理论是远远不行的,用通过一定方式实现才有实用价值。通过本次实验,我加深了对预测分析LR(1)分析法的理解,同时体验到了编译原理中一些算法的巧妙。由于LR(1)分析法程序是一个相当复杂的程序,它需要利用到大量的编译原理,编程技巧和数据结构。后来看了别人的程序,自己试着敲写一遍,都出现了好多问题。又修改了很多问题才实现代码的功能,真的自己敲写一遍都会有很多收获,以后会继续努力的。