语法分析分析器的实现
- 抽象语法树的继承关系
ASTNode:抽象语法树base、Factor:因子*—*所谓因子就是操作符两边可以计算的东西,变量或者数字都行、Expr:表达式
stmt:语句、Block:语句块、IfStmt:if语句、AssignStmt:赋值语句、DeclareStmt:声明语句、ForStmt:for循环语句、FunctionDeclareStmt:声明函数语句
-
最简语法分析
-
- 语法分析器(parser):根据语法规则,将符合(词法单元,lexeme,token),转换成抽象语法树
- 类比:中文分析句子过程
- 和自然语言不同,编译器只能识别[上下文无关文法]
- 一个文法是上下文无关,也就是说,不需要理解这个语言,给定任意这个语言的句子,可以得到一个合理的抽象语法树
- 语法规则
-
-
- 通常用产生式描述语法规则
-
上述产生式可以生成1+1+1或1+1+1+1的句子
-
-
- Expr是非终结符,1是终结符,终结符对应词法单元
-
-
- 递归法求抽象1语法树
-
-
- Expr -> Expr + 1|1可以拆分为两步
-
-
-
-
- 非终结符(递归函数):parseExpr(生成一个非叶子节点)
- 终结符:parseNumber(生成一个叶子节点)
-
-
-
-
- 遇到左递归该如何处理
-
-
-
-
- parseExpr -->parseExpr -->parseExpr…
-
-
-
-
- 消除左递归 Expr -> Expr + 1|1变为Expr -> 1 + Expr | 1
- 例如:解析1+1+1+1的过程
-
-
- 左结合和右结合
-
-
- 同样是1+1+1有两颗不同的抽象语法树
-
-
- 实现1+2+3+4的Parser
-
-
- ParseException
- 封装PeekTokenIterator(继承于PeekIterator)
- 实现1+2+3+4抽象语法树的解析
-
-
左递归的处理
-
- 例如A ->Aa|B的产生式,有没有通用方法转为非左递归形式?
-
-
- 上述产生式只能以B开头
- 可以产生B,Ba,Baa,…的语言
- 因为存在左递归,因为无法使用自顶向下递归法
-
-
- 结论:可以使用两个等效的产生式替代:
-
-
- A ->BA`
- A
->aA
| &(空 )
-
-
一般情况的左递归处理
-
- 例如A -> Aa|Ab|Ay|v的产生式,如何处理
-
-
- 上述产生式只能产生v开头的句子
- 可以产生如v[aby]*的句子
- 存在左递归,无法使用递归向下分析法
-
-
- 结论,可以使用下列产生式替代
-
-
- A ->vA`
- A
-> aA
|bA|yA
|&
-
-
表达式优先级控制
-
- 如何避免左递归
推导出
-
- 表达式优先级表
-
- 表达式优先级判断
-
- 递推和去左递归
-
表达式解析实战
-
- 要点
-
-
- 采用递归向下方法,每个产生式的非终结符对应一个函数
-
-
-
-
- E(),E_(),U(),F()
-
-
-
-
- 产生式的关系对应一个高阶函数
-
-
-
-
- 合并关系,如:E() E_() ->combine(() -> E(),() -> E_())
- 竞争关系,如:E | F -> race(() ->E(),() -> F())
-
-
-
- 优先级表
- 按照优先级解析表达式
-
表达式树的验证
-
- 后序表达式
-
-
- 我们通常用的表达式是表达式数的中序遍历结果
- 后序表达式是表达式树的后序遍历结果
-
-
- 根据后序表达式验证正确性
-
语法分析器整体程序结构
-
- 块和语句
-
-
- 定义语句块和语句
-
Program ->Stmts -> Stmt Stmts | $
Stmt ->IfStmt | WhileStmt | ForStmt | Function…|Block
Block -> { Stmts }
-
-
- 整体结构
-
-
-
- 变量定义
-
DeclateStmt -> var Variable = Expr
-
-
- 变量赋值
-
AssignStmt -> Variable = Expr
-
-
- 提取公共前缀
-
简化下列if语句
简化后
IfStmt -> If(Expr)Block Tail
Tail -> else { Block } | else IfStmt | $
-
-
- Function定义
Function -> func(Args) Type Block
-
函数(参数) 返回类型 函数体
Args -> Type Variable,Args | Type Variable | $
ReturnType -> Type | $
Type:int | string | void | bool | string
-
整体词法分析实现
-
- 定义和赋值
表达式优先级表实现:
/**
* @author :LY
* @date :Created in 2021/4/22 16:41
* @modified By:
*/
public class PriorityTable {
private List<List<String>> table = new ArrayList<>();
public PriorityTable(){
table.add(Arrays.asList(new String[]{"&","|","^"}));
table.add(Arrays.asList(new String[]{"==","!=",">","<",">=","<="}));
table.add(Arrays.asList(new String[]{"+","-"}));
table.add(Arrays.asList(new String[]{"*","/"}));
table.add(Arrays.asList(new String[]{"<<",">>"}));
}
public int size(){
return table.size();
}
public List<String> get(int level){
return table.get(level);
}
}
抽象语法树定义:
/**
*抽象语法树
* @author :LY
* @date :Created in 2021/4/10 9:52
* @modified By:
*/
public abstract class ASTNode {
/* 树 */
protected ArrayList<ASTNode> children = new ArrayList<>();
protected ASTNode parent;
/* 关键信息 */
protected Token lexeme; // 词法单元
protected String label; // 备注(标签)
protected ASTNodeTypes type; // 类型
private HashMap<String, Object> _props = new HashMap<>();
public ASTNode() {
}
public ASTNode(ASTNodeTypes _type, String _label) {
this.type = _type;
this.label = _label;
}
public ASTNode getChild(int index) {
if(index >= this.children.size()) {
return null;
}
return this.children.get(index);
}
public void addChild(ASTNode node) {
node.parent = this;
children.add(node);
}
public Token getLexeme(){
return lexeme;
}
public List<ASTNode> getChildren(){
return children;
}
public void setLexeme(Token token) {
this.lexeme = token;
}
public void setLabel(String s){
this.label = s;
}
public ASTNodeTypes getType(){
return this.type;
}
public void setType(ASTNodeTypes type) {
this.type = type;
}
public void print(int indent) {
if(indent == 0) {
System.out.println("print:" + this);
}
System.out.println(StringUtils.leftPad(" ", indent *2) + label);
for(ASTNode child : children) {
child.print(indent + 1);
}
}
public String getLabel() {
return this.label;
}
public void replaceChild(int i, ASTNode node) {
this.children.set(i, node);
}
public HashMap<String, Object> props() {
return this._props;
}
public Object getProp(String key) {
if(!this._props.containsKey(key)) {
return null;
}
return this._props.get(key);
}
public void setProp(String key, Object value) {
this._props.put(key, value);
}
public boolean isValueType() {
return this.type == ASTNodeTypes.VARIABLE || this.type == ASTNodeTypes.SCALAR;
}
public void replace(ASTNode node) {
if(this.parent != null) {
int idx = this.parent.children.indexOf(this);
this.parent.children.set(idx, node);
//this.parent = null;
//this.children = null;
}
}
}
各种类型的枚举定义
/**
* @author :LY
* @date :Created in 2021/4/10 17:31
* @modified By:
*/
public enum ASTNodeTypes {
BLOCK,//代码块
BINARY_EXPR,//二项表达式 1+1
UNARY_EXPR,//一元表达式 ++i
VARIABLE,//变量
SCALAR,//值类型 1.0 true
IF_STMT,//if语句
WHILE_STMT,//while语句
FOR_STMT,//for语句
ASSIGN_STMT,//赋值语句
FUNCTION_DECLARE_STMT,//定义函数的语句
DECLARE_STMT ,//声明语句
CALL_EXPR,
RETURN_STMT
}
-
- Program
解析入口类
/**
* 程序
* @author :LY
* @date :Created in 2021/4/29 17:57
* @modified By:
*/
public class Program extends Block {
public Program() {
super();
}
public static ASTNode parse( PeekTokenIterator it) throws ParseException {
Program block = new Program();
ASTNode stmt = null;
//解析stmt的语句
while ((stmt = Stmt.parseStmt(it)) != null){
//解析{}中的语句
block.addChild(stmt);
}
return block;
}
}
-
- Block
代码块解析类
/**
* 代码块
* @author :LY
* @date :Created in 2021/4/10 17:41
* @modified By:
*/
public class Block extends Stmt {
public Block() {
super(ASTNodeTypes.BLOCK, "block");
}
public static ASTNode parse(PeekTokenIterator it) throws ParseException {
it.nextMatch("{");
Block block = new Block();
ASTNode stmt = null;
//解析stmt的语句
while ((stmt = Stmt.parseStmt(it)) != null){
//解析{}中的语句
block.addChild(stmt);
}
it.nextMatch("}");
return block;
}
}
-
- Stmt/IfStmt/FunctionStmt
其他都与上面类似,stmt语句解析:
/**
* 语句
* @author :LY
* @date :Created in 2021/4/10 17:39
* @modified By:
*/
public abstract class Stmt extends ASTNode {
public Stmt( ASTNodeTypes _type, String _label) {
super( _type, _label);
}
/**
* 用来解析语句
* @param it
* @return
* @throws ParseException
*/
public static ASTNode parseStmt(PeekTokenIterator it) throws ParseException {
if(!it.hasNext()) {
return null;
}
//向下看两个元素
Token token = it.next();
Token lookahead = it.peek();
it.putBack();
//如果前一个是变量或者等于符号
if (token.isVariable() && lookahead != null && lookahead.getValue().equals("=")){
//产生一个赋值语句
return AssignStmt.parse(it);
}else if (token.getValue().equals("var")){
//如果是var 那么产生一个声明语句
return DeclareStmt.parse( it);
}else if(token.getValue().equals("func")) {
return FunctionDeclareStmt.parse( it);
} else if(token.getValue().equals("return")) {
//ReturnStmt.parse(it);
return ReturnStmt.parse(it);
} else if(token.getValue().equals("if")) {
return IfStmt.parse(it);
} else if(token.getValue().equals("{")) {
return Block.parse(it);
}else {
return Expr.parse(it);
}
}
}
消除左递归核心代码逻辑
/**
* 表达式消除左递归核心逻辑
* @author :LY
* @date :Created in 2021/4/10 19:13
* @modified By:
*/
public class Expr extends ASTNode{
private static PriorityTable table = new PriorityTable();
public Expr(){
super();
}
public Expr( ASTNodeTypes type, Token lexeme) {
super();
this.type = type;
this.label = lexeme.getValue();
this.lexeme = lexeme;
}
//left:E(k) -> E(k) op(k) E(k+1) | E(k+1)
//right:
// E(k) -> E(k+1) E_(K)
// var e = new Expr() e.left=E(k+1); e.op = op(k); e.right=E(k+1) E_(k)
// E_(k) -> op(k) E(k+1) E_(k) | &
//最高优先级处理
// E(t) -> F E_(k) | U E_(k) (U代表括号之类的一元表达式)
// E_(t) ->op(t) E(t) E_(k)| &
public static ASTNode E( int k, PeekTokenIterator it) throws ParseException {
if (k < table.size()-1){
//具有延迟加载,一个函数不产生值,另一个不执行
return combine(it,() ->E(k+1,it),() -> E_(k,it));
}else {
//最高优先级处理
return race(it,
() -> combine(it, () ->F(it),() -> E_(k,it)),
() -> combine(it,() ->U(it), () -> E_(k,it)));
}
}
public static ASTNode E_(int k, PeekTokenIterator it) throws ParseException {
Token token = it.peek();
String value = token.getValue();
if (table.get(k).indexOf(value) != -1){
Expr expr = new Expr(ASTNodeTypes.BINARY_EXPR,it.nextMatch(value));
expr.addChild(
combine(it,
()-> E(k+1, it),
()->E_( k, it)));
return expr;
}
return null;
}
private static ASTNode U(PeekTokenIterator it) throws ParseException {
Token token = it.peek();
String value = token.getValue();
ASTNode expr = null;
if (value.equals("(")){
it.nextMatch("(");
expr = E(0,it);
it.nextMatch(")");
return expr;
}else if (value.equals("++")||value.equals("--") || value.equals("!")){
Token t = it.peek();
it.nextMatch(value);
Expr unaryExpr = new Expr(ASTNodeTypes.UNARY_EXPR, t);
unaryExpr.addChild(E(0,it));
return unaryExpr;
}
return null;
}
private static ASTNode F(PeekTokenIterator it) throws ParseException {
// Token token = it.peek();
// if (token.isVariable()){
// return new Variable(token);
// }else{
// return new Scalar(token);
// }
//拿到参数因子
ASTNode factor = Factor.parse(it);
if(factor == null) {
return null;
}
//确认是否为参数
if(it.hasNext() && it.peek().getValue().equals("(")) {
return CallExpr.parse(factor,it);
}
return factor;
}
/**
* 合并函数 将两个表达式合为一体
* @param it 流
* @param aFunc 合并节点a
* @param bFunc 合并节点b
* @return
* @throws ParseException
*/
public static ASTNode combine(PeekTokenIterator it,ExprHOF aFunc,ExprHOF bFunc) throws ParseException {
ASTNode a = aFunc.hoc();
if (a == null){
return it.hasNext()?bFunc.hoc():null;
}
ASTNode b = it.hasNext()?bFunc.hoc():null;
if (b == null){
return a;
}
Expr expr = new Expr(ASTNodeTypes.BINARY_EXPR,b.lexeme);
expr.addChild(a);
expr.addChild(b.getChild(0));
return expr;
}
/**
* 竞争函数 两个表达式只会存在一个
* @param it
* @param aFunc
* @param bFunc
* @return
* @throws ParseException
*/
private static ASTNode race(PeekTokenIterator it,ExprHOF aFunc,ExprHOF bFunc) throws ParseException {
if (!it.hasNext()){
return null;
}
ASTNode a = aFunc.hoc();
if (a != null){
return a;
}
return bFunc.hoc();
}
public static ASTNode parse(PeekTokenIterator peekTokenIterator) throws ParseException {
return E(0,peekTokenIterator);
}
}
基本代码编写完成,测试代码
-
- 测试
主要测试三段代码
第一段:
PeekTokenIterator it = createTokenIt("if(a){\n" +
"a = 1\n" +
"} else{\n" +
"a = 2\n" +
"a = a * 3" +
"}");
IfStmt stmt = (IfStmt)IfStmt.parse( it);
// parse.print(0);
Variable expr = (Variable)stmt.getChild(0);
Block block = (Block)stmt.getChild(1);
AssignStmt assignStmt =(AssignStmt) block.getChild(0);
Block elseBlock = (Block)stmt.getChild(2);
AssignStmt assignStmt2 = (AssignStmt)elseBlock.getChild(0);
assertEquals("a",expr.getLexeme().getValue());
assertEquals("=",assignStmt.getLexeme().getValue());
assertEquals("=",assignStmt2.getLexeme().getValue());
assertEquals(2,elseBlock.getChildren().size());
测试结果: