1. 什么是算符优先分析算法?
- 这是一种经典的自底向上分析法,简单直观,并被广泛使用。开始主要是对表达式的分析,现在已不限于此,可以用于一大类上下文无关文法。
- 称为算符优先分析是因为这种方法是仿效算术式的四则运算而建立起来的。做算术式的四则运算时,为了保证计算 结果和过程的唯一性,规定了一个统一的四则运算法则, 确定运算符之间的优先关系。
2. 算符优先分析的步骤
- 构造优先关系矩阵(通过FIRSTVT和LASTVT集构造)
- 构造一个输入串(要在两边加上#)和一个符号栈
- 当栈内首个终结符的优先级<或=栈外终结符的优先级时,移进;当栈内首个终结符的优先级>栈外终结符的优先级时,按照文法进行规约。
3. 一个算符优先分析算法的实例
有如下文法,要求实现它的算符优先分析法:
E -> E '+' T | T
T -> T '*' F | F
F -> '(' E ')' | 'i'
输出要求如下:
- 对于每一次压栈,输出一行
I{压入的符号}
(不含大括号),如Ii
是压入i
; - 对于每一次成功的、含有终结符的规约,输出一行
R
(1) ; - 对于失败的规约,输出一行
RE
(2) ; - 对于不能识别或无法比较符号优先关系的栈顶和读入符号,输出一行
E
(2) 。
(1) :因为符号优先文法不区分非终结符,如 T -> F
等的仅含非终结符的规约实际上是不存在的。
遇到 (2) 的情况,输出相应内容后不继续向下分析,直接退出。不管分析结果如何,程序返回值都应为 0
。
为了使读者直观地感受算法过程,省略了构造优先关系矩阵的过程。其优先关系矩阵如下:
具体代码如下:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.EmptyStackException;
import java.util.*;
import static java.lang.System.exit;
public class Main {
//0:error 1:> 2: < 3:= 用数字代表优先关系
//优先关系矩阵matrix
private static int[][] matrix = {
{
1, 2, 2, 2, 1, 1},
{
1, 1, 2, 2, 1, 1},
{
1, 1, 0, 0, 1, 1},
{
2, 2, 2, 2, 3, 0},
{
1, 1, 0, 0, 1, 1},
{
2, 2, 2, 2, 0, 3}};
private static char[] Vt = {
'+', '*', 'i', '(', ')', '#'};//终结符
public static Stack<Character> stack = new Stack<>();
//符号栈
public static char peekVt() {
char a = stack.peek();
if (a == 'N') {
stack.pop();
char b = stack.peek();
stack.push(a);
return b;
}
else
return a;
}//求符号栈中首个终结符
public static int getIndex(char ch){
int i;
for(i = 0;i <= 5;i++){
if(ch == Vt[i]){
return i;
}
}
return -1;
}//获得符号在终结符数组中的位置
public static void reduce(){
char a = stack.pop();
if(a == 'N'){
char b = stack.pop();
if(b == '+'||b == '*'){
if(stack.peek() == 'N'){
System.out.println("R");
return;
}}
}
else if(a == ')'){
char c = stack.pop();
char d = stack.pop();
if(c == 'N' && d == '('){
System.out.println("R");
stack.push('N');}
}
else if(a == 'i'){
//stack.pop();
System.out.println("R");
stack.push('N');
}
else{
System.out.println("RE");
exit(0);
}
return;
}//规约
public static void main(String[] args) throws IOException {
String sentence;
String FileName = args[0];
BufferedReader in = new BufferedReader(new FileReader(FileName));//命令行输入
BufferedReader in = new BufferedReader(new FileReader("D:\\test\\opg.txt"));//本地测试
String OriginalSentence;
while((OriginalSentence = in.readLine()) != null){
sentence = OriginalSentence + '#';
stack.push('#');
for(int i = 0;i < sentence.length();i++){
char c = sentence.charAt(i);
if(stack.empty()){
stack.push(c);
System.out.println("I" + c);
}
else{
char inside = peekVt();
int x = getIndex(inside);
int y = getIndex(c);
//System.out.println("x:"+x);
//System.out.println("y:"+y);
//System.out.println(inside);
if(x == -1||y == -1){
System.out.println("E");
return;
}
int priority = matrix[x][y];
if(priority == 0){
System.out.println("E");
return;
}
else if (priority == 1) {
reduce();
i--;
}
else if (priority == 2) {
stack.push(c);
System.out.println("I" + c);
}
else if (priority == 3) {
if (c == '#' && inside == '#')
return;
stack.push(c);
System.out.println("I" + c);
}
}
}
}
in.close();
}
}