Antlr4初めての経験

$ 00:はじめに

ANTLR 4は、プロセスを読み取るために使用することができるパーサを生成するための強力なツールであり、変換構造化テキストまたはバイナリファイルを実行します。呼ばれる形式言語の文法で記述、ANTLRは自動的にその言語の字句解析器を生成することができます。パーサ解析木を自動的に示して構築することができる生成する方法を入力整合データの文法的構造。ANTLRはまた、自動的に特定のコードを実行するツリートラバーサル、アクセスのツリーノードにまたがることができます。

0x01の:なぜ、この?

私は常に、関連するコンパイラの理論(理論イェジンハオ、イェジンハオツール)は、脆弱性の発見と素晴らしい化学反応かもしれ何かを感じています。9Kマスターおよび関連の事を話しましたが、多くの志を同じくする人がいます。でも、github6年前に、使用するプロジェクトflex+bisonファイルが何生成しますfuzz

そして、flex+bison比較し、antlr4は賢明な参照知恵で見る人の目で、もちろん、間違いなく、より強力な使いやすいです。

これらの事の詳細な調査の後、我々はdomato思考のより深い理解を持っています。実際には、字句解析、トップダウンのセット。私は、本当に素晴らしい、そしてアプリケーションの非常に広い範囲を言っているが、私は知らないどのように効果的な、まだ模索します。

0×02:この記事について

セクション8.4の学習記録の練習で「Antlr4 Definitive Guideの」。この例はのための文法チェッカーの一部であるCymbol言語。

たとえば、次のコード:

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INT  INT X、フロート Y)  {
G()。
I = 3 ; //私はありません宣言(エラー)
G = 4// gが変数(エラー)ではないリターン X + Y。//のx、yが定義されているので、何ら問題はありません }



空隙 G () { int型のx = 0フロート Y。 Y = 9// yが定義されている )(Fと、 //後方参照がOKである Z(); //このような関数(誤差) Y(); // yは関数(誤差)ではない 、X = F。// fが可変でない(エラー) }








文法チェッカーの後、あなたは、未定義のシンボル、エラーの種類(変数としての機能、機能)への参照として、文法の誤りうち、数を見つけることができます。

0x03の例:

1.解析
1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/ **関数と変数を使用した単純な静的に型付けされたプログラミング言語
「言語実装パターン」の本から取られました*。
* /
文法Cymbol。

ファイル:(functionDecl | varDecl)+。

varDecl
:タイプID( '=' expr)は?';'
;
タイプ:「フロート」| 'int型' | 「空」; //ユーザー定義型

functionDecl
:タイプID '('?formalParameters ')'ブロック// "空隙F(INT X){...}"


formalParameters
:formalParameter( '' formalParameter)*
;
formalParameter
:タイプID
;

ブロック: '{' スタット* '}'。//空の可能性文ブロック

STAT:ブロック
| varDecl
| 'もし'式'を' STAT( '他に' STAT)?
| 「リターン」式?';'
| 式expr '='式';' //割り当て
| 式expr ';' // funcを呼び出し


/ * exprの下に、次の非左再帰ルール次のようになります。
exprの[INT _P]
:(' - ' exprの[6]
| '!'式[5]
| ID
| INT
| '('式')'

({ 8> = $ _p} '*'はexpr [9]?
| {7> = $ _p}( '+' | ' - ')?のexpr [8]
| {4> = $ _p} '=='はexpr? [5]
| {10> = $ _p} '['のexpr ']'?
| {9> = $ _p} '(' exprList? ')'?
)*

* /

式expr:ID '(' exprList ')' #コール
| 式expr '['式']' #インデックス
| ' - '式の#ネゲート
| '!' #exprを未
| 式expr '*'式#のMult
| exprの( '+' | ' - ')式expr#加減算
| exprの'=='式#イコール
| ID番号のヴァール
| INT#のInt
| 「(」式「)」#括弧


exprList:exprの( '' 式)*; //引数リスト

K_FLOAT: 'フロート';
K_INT: 'int型';
K_VOID: '無効';
ID:LETTER(LETTER | [0-9])*;
フラグメント
LETTER:[-ZA-Z]。

INT:[0-9] +。

WS:[TNR] + - >スキップ。

SL_COMMENT
: '//' *。?'N' - >スキップ

2.シンボルテーブル

これは本質の一部であり、他の本の著者は、直接、どんなに長い間、使用しないか、コードを理解するために独自のコードを取りました。ここでは、より重要なの一部であるI列のみ:

1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class BaseScope implements Scope {
Scope enclosingScope; // 临近的作用区,如果当前是全局作用域,应该置null
// 因为作用域查找是往前找的,全局已经是最靠前了
Map<String, Symbol> symbols = new LinkedHashMap<String, Symbol>();

public BaseScope(Scope enclosingScope) { this.enclosingScope = enclosingScope; }

public Symbol resolve(String name) {
Symbol s = symbols.get(name);
if ( s!=null ) return s;//在当前作用域找到了,直接返回
//如果临近作用域不空,那么就去临近作用域找
//比如,一个函数内,符号定义没找到,就去往上(全局)找
if ( enclosingScope != null ) return enclosingScope.resolve(name);
//还找不到,那就是未定义,报错
return null; // not found
}

public void define(Symbol sym) {
symbols.put(sym.name, sym);
sym.scope = this; // track the scope in each symbol
}

public Scope getEnclosingScope() { return enclosingScope; }

public String toString() { return getScopeName()+":"+symbols.keySet().toString(); }
}
3. 如何检查

因为目标语言Cymbol允许向前引用,比如:

1
2
3
4
5
6
7
8

int (){
g();
}

void g(){
;
}

所以需要两次遍历,第一次找到所有定义,并放入符号表,将符号表构造好。
接下来进行第二次遍历,这时遇到一个引用,就去找符号表,找到了就是正常,找不到就是有问题。

4. 代码

主要是两个文件,DefPhase.javaRefPhase.java

1. Defphase

关键的问题:在第一次遍历构造符号表的时候,遇到新的作用域,需要把新的作用域的父作用域设置为当前作用域,并且把新的作用域设置为当前作用域。

对于遇到的变量定义直接使用对应的构造符号表的对象去构造就好了。

2. RefPhase

遍历检查每个引用部分,去符号表里查找,找不到就报错。这部分比较简单。

3. checkSymbol
1
2
3
4
5
6
7
8
9
10
11
parser.setBuildParseTree(true);
ParseTree tree = parser.file();
// show tree in text form
//System.out.println(tree.toStringTree(parser));

ParseTreeWalker walker = new ParseTreeWalker();
DefPhase def = new DefPhase();
walker.walk(def, tree);
// create next phase and feed symbol table info from def to ref phase
RefPhase ref = new RefPhase(def.globals, def.scopes);
walker.walk(ref, tree);
5. 结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# muhe @ muheMacBookPro in ~/Study/antlr_study/chapter_8_4 [16:03:46]
$ antlr4 Cymbol.g4

# muhe @ muheMacBookPro in ~/Study/antlr_study/chapter_8_4 [16:03:49]
$ javac Cymbol*.java CheckSymbols.java *Phase.java *Scope.java *Symbol.java -Xlint:deprecation
CheckSymbols.java:9: 警告: [deprecation] org.antlr.v4.runtime中的ANTLRInputStream已过时
import org.antlr.v4.runtime.ANTLRInputStream;
^
CheckSymbols.java:40: 警告: [deprecation] org.antlr.v4.runtime中的ANTLRInputStream已过时
ANTLRInputStream input = new ANTLRInputStream(is);
^
CheckSymbols.java:40: 警告: [deprecation] org.antlr.v4.runtime中的ANTLRInputStream已过时
ANTLRInputStream input = new ANTLRInputStream(is);
^
3 个警告

〜/研究/ antlr_study / chapter_8_4 [午後04時03分56秒]で#muhe @ muheMacBookPro
$のJava CheckSymbolsがvars.cymbol
[]:地元の人々を
機能 <F:色合い>:[<X:TINT>、<Y:TFLOAT>]
地元の人々 :[X、Y]
機能 <G:tVOID>:[]
グローバル:[F、G]
行3:4そのような変数:私は
4行目:4gを可変ません。
このような4:13ライン機能:Z
ライン14:4 yがない関数
8 F変数がありません:15ライン

0×04:参照

"Antlr4 Definitive Guideの"

オリジナル:ビッグボックス  Antlr4初めての経験


おすすめ

転載: www.cnblogs.com/petewell/p/11597497.html