iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 5
0
Software Development

做一個JVM語言系列 第 5

Antlr:文法檔(.g4)練習之二,工程用計算機把值算出來

  • 分享至 

  • xImage
  •  

前面的文章裏,我們已經知道Antlr可以解析簡單的程式碼,並生成文法樹。
它的流程是
LEXER 與PARSER
LEXER 與PARSER,
LEXER把TOKEN一段一段切出來,而與PARSER是把句子的文法樹構建出來。
那如果真的要把計算式的值算出來,要怎麼做呢?

在文法檔(.g4)裏,有一個LABEL(視別標籤)的功能,它可以讓設計者把每個句子,每個關鍵字視別出來,
在生成CODE時,產生方法,示範如下:

grammar LabeledExpr;
import CommonLexerRules;

prog 	: stat+ ;


stat 	: expr NEWLINE			# printExpr
	| ID '=' expr NEWLINE		# assign
	| NEWLINE			# blank
	;

expr	: expr op=('*'|'/') expr		# Muldiv
	| expr op=('+'|'-') expr		# AddSub
	| INT				# int
	| ID				# id
	| '(' expr ')'			# parens
	;

MUL	: '*';
DIV	: '/';
ADD	: '+';
SUB	: '-';

在文法檔裏,# printExpr ,# assign,# blank,# Muldiv,# AddSub,
猛一看以為是註解,它就是所謂的LABEL(視別標籤),這是Antlr的一個特別功能,
它在產生程式碼時,會把這些標籤納入程式碼中,
配合Antlr的visitor設計模式,就可以去visit(尋訪)被解析的程式中的內容(context),
例如:
將上述內容存成LabeledExpr.g4這個文法檔。
然後,

$ antlr4 -no-listener -visitor LabeledExpr.g4

Antlr會幫你產生尋訪被解析程式的代碼,
打開LabeledExprVistior.java, 裏面有,

public interface LabeledExprVisitor<T> extends ParseTreeVisitor<T> {
	/**
	 * Visit a parse tree produced by {@link LabeledExprParser#prog}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitProg(LabeledExprParser.ProgContext ctx);
	/**
	 * Visit a parse tree produced by the {@code printExpr}
	 * labeled alternative in {@link LabeledExprParser#stat}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitPrintExpr(LabeledExprParser.PrintExprContext ctx);
	/**
	 * Visit a parse tree produced by the {@code assign}
	 * labeled alternative in {@link LabeledExprParser#stat}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitAssign(LabeledExprParser.AssignContext ctx);
	/**
	 * Visit a parse tree produced by the {@code blank}
	 * labeled alternative in {@link LabeledExprParser#stat}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitBlank(LabeledExprParser.BlankContext ctx);
	/**
	 * Visit a parse tree produced by the {@code parens}
	 * labeled alternative in {@link LabeledExprParser#expr}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitParens(LabeledExprParser.ParensContext ctx);
	/**
	 * Visit a parse tree produced by the {@code Muldiv}
	 * labeled alternative in {@link LabeledExprParser#expr}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitMuldiv(LabeledExprParser.MuldivContext ctx);
	/**
	 * Visit a parse tree produced by the {@code AddSub}
	 * labeled alternative in {@link LabeledExprParser#expr}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitAddSub(LabeledExprParser.AddSubContext ctx);
	/**
	 * Visit a parse tree produced by the {@code id}
	 * labeled alternative in {@link LabeledExprParser#expr}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitId(LabeledExprParser.IdContext ctx);
	/**
	 * Visit a parse tree produced by the {@code int}
	 * labeled alternative in {@link LabeledExprParser#expr}.
	 * @param ctx the parse tree
	 * @return the visitor result
	 */
	T visitInt(LabeledExprParser.IntContext ctx);
}

文法檔裏的標籤(如#int )就會產生visitInt的方法。#id 產生visitId。它的規則是visit標籤

因為是計算機的用途,目前是用於計算整數,我們就實作這個interface,把integer 代入型別T.

public class EvalVisitor extends LabeledExprBaseVisitor<Integer>{
	Map<String,Integer>memory = new HashMap<String,Integer>();

..........
	@Override
	public Integer visitMuldiv(LabeledExprParser.MuldivContext ctx){ 
				  //LabeledExprParser.MuldivContext ctx
		int left = visit(ctx.expr(0));		
		int right = visit(ctx.expr(1));
		if (ctx.op.getType()== LabeledExprParser.MUL) return left*right;
		return left/right;
	}

這裏示範乘法及除法 運算式時,要求出值的做法。

對照文法檔(.g4)裏的
對照的文法。
expr : expr op=('*'|'/') expr # Muldiv
expr在程式裏出現,左邊是expr(0),右邊是expr(1),op 也出現了,而MUL,出現在
MUL : '*';

Antlr 這套程式語言產生器,會根據你的文法,
一一產生想對應的方法(visitXXXX),句子內容(ctx),內容裏的組成元素( expr,op),
簡化你寫對應的程式。

小結: 本次內容,描述Antlr的 visitor設計模式,用以尋訪每一句子,及句中的元素,方便使用寫出對應的程式碼。


上一篇
Antlr:文法檔(.g4)練習之一,四則運算式的工程用計算機
下一篇
Antlr:Listener監聽者模式
系列文
做一個JVM語言12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言