$ 00:はじめに
ANTLR 4は、プロセスを読み取るために使用することができるパーサを生成するための強力なツールであり、変換構造化テキストまたはバイナリファイルを実行します。 呼ばれる形式言語の文法で記述、ANTLRは自動的にその言語の字句解析器を生成することができます。 パーサ解析木を自動的に示して構築することができる生成する方法を入力整合データの文法的構造。 ANTLRはまた、自動的に特定のコードを実行するツリートラバーサル、アクセスのツリーノードにまたがることができます。
0x01の:なぜ、この?
私は常に、関連するコンパイラの理論(理論イェジンハオ、イェジンハオツール)は、脆弱性の発見と素晴らしい化学反応かもしれ何かを感じています。 9Kマスターおよび関連の事を話しましたが、多くの志を同じくする人がいます。 でも、 github
6年前に、使用するプロジェクト 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 。 リターン X + Y。 } 空隙 G () { int型 のx = 0 。 フロート Y。 Y = 9 。 )(Fと、 Z(); Y(); 、X = 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; 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 ; } public void define (Symbol sym) { symbols.put(sym.name, sym); sym.scope = this ; } 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.java
和RefPhase.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(); ParseTreeWalker walker = new ParseTreeWalker(); DefPhase def = new DefPhase(); walker.walk(def, tree); 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
$ antlr4 Cymbol.g4 $ 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 个警告 $の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初めての経験