CDM之ANTLR學習
ANTLR是什么
ANTLR是一個解析器生成工具,可以根據你書寫的文法文件,自動生成可以解析該文法的解析器(Parser).其強大的功能遠不止這些.
文法文檔(Grammar Lexicon)
Lexicon是按ANTLR規范書寫的文件,在這個文件中指定你要解析的文法,ANTLR再根據這個文件生成對應的解析器.
標識符(Identifiers)
詞法單元和詞法規則通常以大寫字母命名
解析規則(parser rule) 以小寫字母開頭命名(駝峰命名法)
例如:
1
2
ID, LPAREN, RIGHT_CURLY //token names/rule
expr, simpleDclarator, d2, header_file //rule names
ANTLR還支持unicode編碼的字符命名
文字(Literals)
ANTLR不區分字符和字符串.所有的字符串(這里是指出現在源文件中的需要被識別的字符串)都是由單引號引用起來的字符,但是像這樣的字符串中不包括正則表達式.支持unicode和轉義符號例如
1
2
3
4
',' , 'if', '>=',
' \''//轉義的單引號
'\u00E8' //法語中的字符è
'\n', '\r' //換行 回車
動作(Actions)
動作是用目標語言書寫的代碼塊.嵌入的代碼可以出現在:
@header?@members這樣的命名動作中
解析規則和詞法規則中
異常捕獲中
解析規則的屬性部分(返回值,參數等)
一些規則可選元素中
關鍵字(Keywords)
ANTLR中有一些保留關鍵字,例如:
1
import,?fragment,?lexer,?parser,?grammar,?returns,?locals,?throws,?catch,?finally,?mode,?options,?tokens
語法結構(Grammar Structure)
語法結構如下
|Grammar |
| ————- |
| /Optional javadoc style comment*/|
|?grammer?Name; |
|?options?{…}; |
|?import?…; |
|?tokens?{…}; |
|?channels?{…}; |
|?@actionName** {…}; |
| |
| rule1 //parser and lexer rules |
| … |
| ruleN |
文件命名必須和grammar命名相同,如?grammar T,文件名必須命名為T.g4.
options,imports,token,action的聲明順序沒有要求,但一個文件中options,imports,token最多只能聲明一次.grammar是必須聲明的,同時必須至少聲明一條規則(rule),其余的部分都是可選的.
規則(rules)
規則的聲明遵循以下格式:
1
2
3
4
ruleName : alternative1 | ... | alternativeN ;
//定義類型
type : 'int' | 'unsigned' | 'long'
引入(imports)
ANTLR中的引入機制類似于OO中的繼承.它會從引入的文件繼承所有的規則,詞法單元,動作.然后主文件中的元素會”覆蓋”引入文件中的重名元素.
嵌套引用的合并規則比較復雜,詳見官方文檔
詞法單元(Tokens Section)
1
tokens?{Token1?...?TokenN}
例如為向量表示定義虛詞法單元:
1
2
3
4
5
6
7
8
9
grammar VecMathAST
options{output=AST;}
tokens{VEC;}
statlist : stat+ ;
stat : ID '=' expr -> ^('=' ID expr)
| 'print' expr -> ^('print' expr);
expr : multExpr ('+' ^ multExpr)*;
multExpr : primary (('*'^|'.'^) primary)*;
primary : INT | ID | '[' expr (',' expr)* ']' -> ^(VEC expr+);
動作(Actions at the Grammar Level)
針對java,有兩個已經定義好的action:header和members
@header在生成的目標代碼中的類定義之前注入代碼
@members在生成的目標代碼中的類定義里注入代碼(例如類的屬性和方法)
1
2
3
4
5
6
7
8
9
10
11
12
13
grammar Count;
@header {
pacakage foo;
}
@members{
int count = 0;
}
list @after{System.out.println(count+"ints");} : INT {count++;} (',' INT {count++})*
;
INT: [0-9]+;
解析器規則(Parser Rules)
解析器由一組解析器規則組成.java應用通過調用生成的規則函數(每個規則會生成一個函數)來啟動解析.
基本形式如下,用?|?操作符分割多個選項
1
stat?:?restat?|?'break'?';'?|?'continue'?';'?;
可選標簽(Alternative Labels)
可以在規則中添加標簽,ANTLR會根據標簽生成與規則相關的解析樹的事件監聽函數,使我們更加精準的控制解析過程.用?#?操作符定義一個標簽
用法如下:
1
2
3
grammar T;
stat: 'return' e ';' # Return
| 'break' ';' # Break
ANTLR會為每個標簽生成一個rule-context類.
1
2
3
4
5
6
public interface AListener extends ParseTreeListener {
void enterReturn(AParser.ReturnContext ctx);
void exitReturn(AParser.ReturnContext ctx);
void enterBreak(AParser.BreakContext ctx);
void exitBreak(AParser.BreakContext ctx);
}
同一個標簽可以加在多個規則選項上(multiple alternatives),但是標簽命名不可以和規則名沖突
規則上下文對象(Rule Context Objects)
ANTLR為每個規則生成一個上下文對象,通過這個對象可以訪問規則定義中的其他規則的引用.根據規則定義中的其他規則的引用數量不同,生成對象中包含的方法也不同.例如:
1
2
3
4
5
6
7
inc : e '++';
//generates this context class
public static class IncContext extends ParserRuleContext {
public EContext e() { ... } // return context object associated with e
...
}
1
2
3
4
5
6
7
8
field : e '.' e;
//generates this context class
public static class FieldContext extends ParserRuleContext {
public EContext e(int i) { ... } // get ith e context
public List
...
}
規則元素標簽(Rule Element Labels)
可以用?=?操作符為規則中的元素添加標簽,這樣會在規則的上下文對象中添加元素的字段.
例如:
1
2
3
4
5
6
7
8
9
stat: 'return' value=e ';' # Return //將e的context作為一個字段添加到 ReturnContext中
| 'break' ';' # Break
;
//generates context class
public static class ReturnContext extends StatContext {
public EContext value;
...
}
+=?操作符可以很方便的記錄大量的token或者規則的引用
1
2
3
4
5
6
array : '{' el+=INT (',' el+=INT)* '}' ;
//ANTLR generates a List field in the appropriate rule context class:
public static class ArrayContext extends ParserRuleContext {
public List
...
}
規則元素(Rule ELements)
規則元素指定了解析器在具體時刻應該執行什么任務.元素可以是規則(rule),?詞法單元(token),?字符串文字(string literal)等
T?token
‘literal’ ? ? ?字符串文字
r ? ? ?規則
r[args] ? ? ?向規則函數中傳遞參數,參數的書寫規則是目標語言,用逗號分隔
.?通配符
{action} ? ? ?動作,在元素的間隔中執行
{p} ? ? ?謂詞
支持邏輯非操作符:~
子規則
規則中包含的可選塊稱為子規則(被封閉在括號中).子規則也可以看做規則(rule),但是沒有顯式的命名.子規則不能定義局部變量,也沒有返回值.如果子規則只有一個元素,括號可以省略.
子規則有四種
例如:
(x|y|z) ? ? ?只匹配一個選項
(x|y|z)? ? ? ?匹配一個或者不匹配
(x|y|z)* ? ? ?匹配零次或多次
(x|y|z)+ ? ? ?匹配一次或多次
參考:
https://developer.ibm.com/zh/articles/j-lo-antlr/
https://theantlrguy.atlassian.net/wiki/display/ANTLR4/ANTLR+4+Documentation
http://yijun1171.github.io/2015/03/30/ANTLR4%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E8%AF%AD%E6%B3%95%E5%AD%97%E5%85%B8-Grammar-Lexicon
云數據遷移 CDM 面向對象編程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。