首页 > 编程知识 正文

现代汉语语法研究教程,新编英语语法教程

时间:2023-05-03 09:20:39 阅读:225380 作者:2689

目录 1. 开心的麦片: 使用antlr定义的语法树遍历顺序——listener 1.1. 类的继承关系1.2. 需要与antlr遍历类ParseTreeWalker一起使用1.3. 对同一非终结符的不同产生式进行标记 1.3.1. 不标记的话实现起来复杂1.3.2. 解决方法: 标记产生式 1.4. 特点1.5. 例子 2. 方法二: 程序员需要自定义语法树遍历顺序——visit 2.1. 类的继承关系2.2. 特点2.3. 例子 3. 方法三: 将动作代码嵌入文法产生式文法

开心的麦片: 使用antlr定义的语法树遍历顺序——listener

antlr生成类ParseTreeListener,这个类里面包含了进入语法树种每个节点和退出每个节点时要进行的操作。本质上,就是树的前序和后序遍历。

类的继承关系

ANTLR自动生成 XXXListener接口,在类xxxBaseListener中实现所有的方法程序员需要做的是集成xxxxBaseListener类 需要与antlr遍历类ParseTreeWalker一起使用 对同一非终结符的不同产生式进行标记 不标记的话实现起来复杂

listeners/Expr.g4
grammar Expr;
s:e;
e:eop=MULTe //MULTis’*’

e op=ADD e // ADD is ‘+’INT

;

listener需要判断哪个e
listeners/TestEvaluator.java
public void exitE(ExprParser.EContext ctx) {
if ( ctx.getChildCount()==3 ) { // operations have 3 children
int left = values.get(ctx.e(0));
int right = values.get(ctx.e(1));
if ( ctx.op.getType()==ExprParser.MULT ) {
values.put(ctx, left * right);
}
else {
values.put(ctx, left + right);
} }
else {
values.put(ctx, values.get(ctx.getChild(0))); // an INT
} }上下文EContext将三个可选择的产生式放到了同一个上下文
public static class EContext extends ParserRuleContext {
public Token op;// derived from label op
public List e() { … } */ get all e subtrees
public EContext e(int i) { … } /* get ith e subtree
public TerminalNode INT() { … } // get INT node if alt 3 of e

} 解决方法: 标记产生式

e : e MULT e # Mult

e ADD e # AddINT # Int

;

ANTLR为每个产生式生成函数
public interface LExprListener extends ParseTreeListener { void enterMult(LExprParser.MultContext ctx);
void exitMult(LExprParser.MultContext ctx);
void enterAdd(LExprParser.AddContext ctx);
void exitAdd(LExprParser.AddContext ctx); void enterInt(LExprParser.IntContext ctx); void exitInt(LExprParser.IntContext ctx); …
}ANTLR 生成特定的上下文对象,EContext的子类IntContext has only an INT() method 特点 程序员不需要显示定义遍历语法树的顺序,实现简单缺点,也是不能显示控制遍历语法树的顺序,visit方式可以动作代码与文法产生式解耦,利于文法产生式的重用没有返回值,需要使用map、栈等结构在节点间传值 例子


语法树遍历时,函数调用顺序

方法二: 程序员需要自定义语法树遍历顺序——visit 类的继承关系

特点 程序员可以显示定义遍历语法树的顺序不需要与antlr遍历类ParseTreeWalker一起使用,直接对tree操作动作代码与文法产生式解耦,利于文法产生式的重用visitor方法可以直接返回值,返回值的类型必须一致,不需要使用map这种节点间传值方式,效率高 例子

PropertyFileVisitor loader = new PropertyFileVisitor();
loader.visit(tree);
System.out.println(loader.props); // print results

方法三: 将动作代码嵌入文法产生式文法

不利于文法产生式在不同的语言中重用

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。