一个简单的语法分析器(后缀式转换)

时间:2021-04-04 16:47:57

编译原理很神奇,经过一次次小小的步骤,然后奇迹就出现了。

对于中缀式转后缀式,这已经不算一个很困难的问题了,之前也学了很多能够解决此问题的数据结构和算法,比如栈和表达式树。今天算是又多学了一种解法。不同的是,该方法更强劲。

构造产生式

定义一下字母表 {0-9+-*/ \t\n}

产生式:

expr -> expr + term
  | expr - term
  |

term

     
term -> term * factor
  | term / factor
  | factor
     
factor -> digits | (expr)
     
digits -> digits digit | -digits
digit -> 0|1|2|3|4|5|6|7|8|9

 

 

 

 

 

 

 

 

 

 

 

 

可以看到,该生成产生式支持 "()"的嵌套和"-"(负)运算, 例如 12+-3/(21-7+(1)) 是支持的.

该产生式不能处理空白字符, 例如 1 + 2,想要支持这样的语法,只需要在编写程序的时候多一个判断,即如果 向前看(lookahead) 符号为空白符,跳过即可.

 

处理左递归

为了能够顺利的编写程序,要首先处理掉产生式中存在的左递归. 

expr -> expr + term
  | expr - term
  | term 

 

 

 

 

对于上面的产生式,我们可以做如下处理

expr -> term rest
     
rest  ->

+ term rest

  |

- term rest

  |

ε

 

 

 

 

 

 

 

如此便消除了左递归,我们可以将该产生式用另一种方式表示出来

expr -> term ((+|-) term)*

 

 

注:其中 A*的意思是 A 可以出现 任意次

 

语义动作

接下来把表达式翻译成后缀形式的语义动作:

expr -> expr + term {print ('+')}
  | expr - term {print ('-') }
  |

term

 
       
term -> term * factor {print('*')}
  | term / factor {print('/') }
  | factor  
       
factor -> digits | (expr)  
       
digits -> digits digit | -digits {print(' ')}
digit -> 0|1|2|3|4|5|6|7|8|9 {print(digit)}

 

 

 

 

 

 

 

 

 

 

 

 

编写代码

最后的任务就是编写代码啦

 

一个简单的语法分析器(后缀式转换)一个简单的语法分析器(后缀式转换)
public class Parser {
private char lookahead;

public Parser() throws IOException {
readch();
}

// 能够处理多余的空白符
public boolean Is(char t) throws IOException {
while (lookahead == ' ' || lookahead == '\t') readch();
if (lookahead == t) return true;
else return false;
}

public void readch() throws IOException {
lookahead
= (char) System.in.read();
}

public void match(char t) throws IOException {
if (lookahead == t) {
readch();
}
else throw new Error("syntax error");
}

public boolean digit() throws IOException {
if (Character.isDigit(lookahead)) {
print(lookahead);
readch();
return true;
}
else return false;
}

public void digits() throws IOException {
if (Is('-')) {
match(
'-'); print('-'); digits();
}
else while (digit()) ;
}


public void factor() throws IOException {
if (Is('(')) {
match(
'('); expr();
if (!Is(')')) {
throw new Error("\"(\" 匹配错误");
}
match(
')');
}
else {
digits(); print(
' ');
}
}


public void term() throws IOException {
factor();
while (Is('*') || Is('/')) {
char t = lookahead; match(lookahead); factor(); print(t); print(' ');
}
}

public void expr() throws IOException {
term();
while (Is('+') || Is('-')) {
char t = lookahead; match(lookahead); term(); print(t); print(' ');
}
}

public void print(char ch) {
System.out.print(ch);
}
}


public class Postfix {
public static void main(String[] args) {

try {
Parser parser
= new Parser();
parser.expr();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
View Code