程式語言試驗之Antlr4+Java實現"圈2"
阿新 • • 發佈:2019-01-04
此文涉及的原始碼版本: program-in-chinese/quan2
宣告 程式碼來源 How to Create Language Using Antlr4
本作主要作為學習Antlr, 以及實踐中文命名之用. 目標不是一個實用的程式語言.
個人感覺這樣可以比較容易的用原型來嘗試和演示不同語法設計, 如果有更簡單的途徑請不吝賜教. 歡迎各種自行修改~碰到任何問題也歡迎一同探討.
下面是"圈2"語言的示例程式碼:
開始 使 甲 為 5 使 乙 為 10 加 3 到 乙 加 乙 到 甲 加 甲 到 乙 列印 乙 列印 3 結束
附上需要自行編寫的三個檔案:
Antlr4的語法定義檔案:
按照README說明, Antlr可以據此自動生成四個分析器相關類檔案. T字首是由於Antlr約定大寫開頭是Token定義. 識別符號支援中文.
grammar 圈2; 程式 : '開始' 宣告+ '結束'; 宣告 : 賦值 | 加 | 列印 ; 賦值 : '使' T識別符號 '為' (T數 | T識別符號) ; 列印 : '列印' (T數 | T識別符號) ; 加 : '加' (T數 | T識別符號) '到' T識別符號 ; T識別符號 : ('a' .. 'z' | 'A' .. 'Z' | '\u4E00'..'\u9FA5' | '\uF900'..'\uFA2D')+ ; T數 : [0-9]+ ; T空白 : [ \n\t]+ -> skip;
定製監聽器:
通過對每種語句分析後進行對應處理, 實質上起了直譯器的作用.
public class 定製監聽器 extends 圈2BaseListener {
private Map<String, Integer> 變量表;
public 定製監聽器() {
變量表 = new HashMap<>();
}
@Override
public void exit賦值(賦值Context 上下文) {
// 賦值語句分析結束時執行此方法
String 變數名 = 上下文.T識別符號(0).getText();
// 如果語句中有兩個變數(識別符號), 那麼取第二個變數的值, 否則取數的值
int 值 = 上下文.T識別符號().size() > 1
? 變量表.get(上下文.T識別符號(1).getText())
: Integer.parseInt(上下文.T數().getText());
// 更新變數值
變量表.put(變數名, 值);
}
@Override
public void exit加(加Context 上下文) {
// 加語句分析結束時執行此方法
String 變數名 = 上下文.T識別符號().size() > 1 ? 上下文.T識別符號(1).getText() : 上下文.T識別符號(0).getText();
int 新增值 = 上下文.T識別符號().size() > 1 ? 變量表.get(上下文.T識別符號(0).getText())
: Integer.parseInt(上下文.T數().getText());
變量表.put(變數名, 變量表.get(變數名) + 新增值);
}
@Override
public void exit列印(列印Context 上下文) {
// 列印語句分析結束時執行此方法
String 輸出 = 上下文.T識別符號() == null ? 上下文.T數().getText() : 變量表.get(上下文.T識別符號().getText()).toString();
System.out.println(輸出);
}
}
執行器:
讀取檔案輸入, 呼叫附著了定製監聽器的分析器
public class 執行器 {
public static void main(String[] 引數) {
try {
ANTLRInputStream 輸入 = new ANTLRInputStream(new FileInputStream(引數[0]));
圈2Lexer 詞法分析器 = new 圈2Lexer(輸入);
圈2Parser 語法分析器 = new 圈2Parser(new CommonTokenStream(詞法分析器));
語法分析器.addParseListener(new 定製監聽器());
// 開始分析
語法分析器.程式();
} catch (IOException e) {
e.printStackTrace();
}
}
}
尚未探索如何用Antlr4實現無空格語法設計(不允許識別符號中出現關鍵字應該可以做到, 但那樣限制太多)