コンパむル。 2文法

前回の投皿には倚くのコヌドがあり、意芋によっおは十分な説明がありたせんでした。 代わりに、今床は倚くの理論がありたすが、実際にはほずんど到達したせん。



さらに投皿

  1. ショップマシン
  2. 正匏な文法
  3. LR解析


ショップマシン



前回、正芏衚珟の問題を特定し、その䞊にテキストを解析するためのDFAを構築したした。ブラケットがネストの同じレベルにあるかどうかを刀断するこずは䞍可胜です。 正芏衚珟を䜿甚するず、さらに狭い問題でさえ解決するこずは䞍可胜です。 {*} *のような文字列をチェックしお、数量が{ quantity }ず等しいかどうかを確認したす。 それずは逆に、そのような正芏衚珟を䜜成できるずしたす。 したがっお、それからDFAを構築するこずができたす。これにより、適切な行ず䞍適切な行が区別されたす。 結果のDFAにN個の状態がある堎合、タむプ{ N +1 ぀たり " N +1回{ "の行で、オヌトマトンはいく぀かの状態「ルヌプ」で耇数回蚪問したす。 そのため、行の先頭に新しい文字{を远加するず、同じサむクルでもう䞀床マシンを実行できたす-眮換に気付かないでしょう。 その結果、マシンは適切なラむン{ N + 1 } N + 1ず䞍適切なラむン{ N + M + 1 } N + 1を区別できなくなりたす。  Mはマシンで怜出されたルヌプの長さです。それは{行の先頭に远加されたす。



蚀い換えれば、DFAは十分なメモリがないため、ネストされた構造を認識できたせん。芚えおいるのは1〜N 珟圚の状態番号の倀だけです。 より倧容量のマシンが必芁であり、そのメモリは必芁に応じお無制限に拡倧できたす。



珟圚の状態に加えお、 ストアメモリを備えたオヌトマトンには、文字を曞き蟌むこずができるスタックがありたす。 各ステップで、マシンは次の入力文字ずスタックの先頭文字を読み取りたす。 トリプル珟圚の状態、入力シンボル、スタックからのシンボルに埓っお、マシンは、読み取りシンボルの代わりに切り替える状態ずスタックに曞き蟌むものを遞択したす。 スタックぞの曞き蟌みはオプションです。読み取り文字をそこから単玔に消去できたす。 そのため、動䜜䞭のスタックは拡倧ず瞮小の䞡方を行うこずができたす。



甚語に関しお自動販売機は店舗の自動販売機ずは関係ありたせん。 奇劙なこずに、ストアマシンは、スタックの叀兞的な実装であるマシンストア図を参照にちなんで呜名されおいたす。カヌトリッゞの最䞊郚の芁玠にのみアクセスできたす。



これで、元の問題を解決できたす。 {ず}が行にあるかどうかを確認したす。 各{を読み取り、スタックに曞き蟌みたす。 各}を読み取り、スタックから{を消去したす。



状態1{
             スタック蚘号{EOF空のスタック
入力文字
       {write {{、1にずどたる{}、1にずどたる
       }䜕も曞かないで、行2に収たらない1
      EOF文字列が収たらない2文字列が収たる3


状態2考慮}
             スタック蚘号{EOF空のスタック
入力文字
       {ラむンが収たらない4ラむンが収たらない4
       }䜕も曞かないでください。2行目にずどたるこずはできたせん5
      EOF文字列が収たらない6文字列が収たる7
泚
  1. 行は}で始たりたす
  2. 行の先頭に耇数の{がありたすが、それらの埌には1぀ではありたせん}
  3. 行は空です
  4. 埌}行には再び{
  5. } {以䞊スタックは終了したしたが、入力はありたせん
  6. }より小さい{ 入力は終了したが、スタックはない
  7. 同様に{ず} スタックず入力は同時に終了したした


容量の倧きいマシンに加えお、構文を蚭定する新しい方法がただ必芁です-正芏衚珟よりも柔軟です。



正匏な文法



任意のネストをサポヌトする蚀語構造を決定するために、たずえばネストされたブラケットの䞊蚘の問題に察しお、文字「端末」ず倉数「非端末」で構成される「掚論芏則」を䜿甚し始めたした。
有効 '{'有効 '}';
有効;
巊、コロンの前-倉数。 右偎には、そこから取埗できるテキストがあり、定矩されおいる倉数ぞの再垰参照を含む倉数を含めるこずができたす。



スペヌスを節玄するために、同じ倉数の代替定矩を分割できたす| 
有効 '{'有効 '}' |  ;


より意味のある䟋は、算術匏の文法です。
 EXPRNUM |  EXPR OP EXPR;
 NUMDIGIT |  NUM DIGIT;
 DIGIT '0' |  '1' |  '2' |  '3' |  '4' |  '5' |  '6' |  '7' |  '8' |  '9';
 OP '+' |  '-' |  '*' |  '/';


このタむプの文法はcontext-freeず呌ばれ、倉数の定矩がコンテキストに䟝存しないこずを瀺したす。たずえば、NUMの前に「0x」が付いおいおも、垞に10進数の文字列に䞀臎したす。 実際には、効果的な構文解析メ゜ッドがないため、状況䟝存文法は䜿甚されたせん。



したがっお、文法に埓っお、匏22+3*4-5



は次のように認識されたす。
   「2」「2」「+」「3」「*」「4」「-」「5」
 DIGIT DIGIT OP DIGIT OP DIGIT OP DIGIT
  NUM DIGIT OP NUM OP NUM OP NUM
    NUM OP EXPR OP EXPR OP EXPR
     EXPR OP EXPR OP EXPR
            EXPR OP EXPR
                     EXPR
たたは倚分そう
   「2」「2」「+」「3」「*」「4」「-」「5」
 DIGIT DIGIT OP DIGIT OP DIGIT OP DIGIT
  NUM DIGIT OP NUM OP NUM OP NUM
    NUM OP EXPR OP EXPR OP EXPR
     EXPR OP EXPR OP EXPR
            EXPR OP EXPR
                             EXPR
前者の堎合、匏は巊偎の合蚈ず右偎の差の積ずしお認識されたす。 第二に-算術の芏則に埓っお。 指定された2぀を陀き、他のオプションも可胜です。



単䞀の匏に耇数の「解析ツリヌ」がある堎合、疑問が生じたす。パヌサヌはどちらを遞択する必芁がありたすか



同様の問題は正芏衚珟にありたした「。」、「]」、「。」の行に「quick brown fox」を適甚するず、$ 1 =「quick brown」ず$ 2 =「fox」、たたは$ 1 =“迅速な「および$ 2 = "茶色のキツネ」。 正芏衚珟は、「貪欲に」動䜜するこずに同意し、巊から右に行を読み、各サブ匏に可胜な限り倚くの適切な文字を取り蟌みたす。 したがっお、実際には「クむックブラりン」ず「フォックス」が埗られたす。



文法にはそのような取り決めはありたせん。 文法があいたいな分析を可胜にする堎合、これは悪い、䟡倀のない文法であり、別の文法を考え出す必芁がありたす。 たずえば、巊から右にすべおのアクションを実行する垂堎取匕蚈算機の文法は次のようになりたす。

EXPR: NUM | EXPR OP NUM ;

NUM: DIGIT | NUM DIGIT ;

DIGIT: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;

OP: '+' | '-' | '*' | '/' ;





珟圚、EXPR定矩では、2番目のオペランドは垞に裞の数倀であるため、解析は次のようにしかできたせん。
   「2」「2」「+」「3」「*」「4」「-」「5」
 DIGIT DIGIT OP DIGIT OP DIGIT OP DIGIT
  NUM DIGIT OP NUM OP NUM OP NUM
    NUM OP NUM OP NUM OP NUM
     EXPR OP NUM OP NUM OP NUM
            EXPR OP NUM OP NUM
                     EXPR OP NUM
                             EXPR


代わりに加算よりも乗算の優先順䜍を維持したい堎合、EXPRは積の合蚈ずしお定矩する必芁がありたす 。

EXPR: TERM | EXPR '+' TERM | EXPR '-' TERM ;

TERM: NUM | TERM '*' NUM | TERM '/' NUM ;

NUM: DIGIT | NUM DIGIT ;

DIGIT: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;



'2' '2' '+' '3' '*' '4' '-' '5'

DIGIT DIGIT '+' DIGIT '*' DIGIT '-' DIGIT

NUM DIGIT '+' NUM '*' NUM '-' NUM

NUM '+' TERM '*' NUM '-' TERM

TERM '+' TERM '-' TERM

EXPR '+' TERM '-' TERM

EXPR '-' TERM

EXPR







プログラミング蚀語では、同様のあいたいさは珍しくありたせんが、C ++ではすべおのステップで正しいです。コメンテヌタヌは、C ++コンパむラの最初から最埌たでの開発に関する玠晎らしい蚘事「珍しい職業」に蚀及したした。

これは詳现を掘り䞋げる時期ではありたせんが、最も簡単な䟋はif (1) if (2) foo(); else bar();



if (1) if (2) foo(); else bar();



if (1) { if (2) foo(); else bar(); }



ように解釈できたすif (1) { if (2) foo(); else bar(); }



if (1) { if (2) foo(); else bar(); }



if (1) { if (2) foo(); else bar(); }



、たたはif (1) { if (2) foo(); } else bar();



if (1) { if (2) foo(); } else bar();



文法のコンパむラが解釈の1぀を犁止するこずに泚意しない堎合。

あいたいさのない文法を曞くこずは重芁なスキルです。



LR解析



ストアオヌトマトンに文法を認識させる方法は

入力行を1文字ず぀読み取り、読み取った文字をスタックに曞き蟌み shift たす。 文法芏則に䞀臎するスタックの最䞊郚でシヌケンス文字ず倉数が収集されるずすぐに、マシンはそのすべおをスタックから抌し出し、䞀臎する芏則の巊偎の倉数に眮き換えたす 畳み蟌み 。 マシンのすべおの䜜業は、䞀連のシフトず畳み蟌みです。



興味深い点マシンは、どのキャラクタヌがスタックにあるかを本圓に気にしたせん。 それでも同じように、圌はそれらを文法のルヌルず比范するこずはできたせん。 代わりに、珟圚の状態に基づいお畳み蟌みに適甚するルヌルを遞択したす。 圌は、折りたたみ埌にどの状態になるかを知るために、スタックが必芁です。 これを行うために、シフト䞭に、圌はシンボルずずもに珟圚の状態をスタックに曞き蟌みたす。 畳み蟌み䞭に、スタックから消去されたすべおの文字の䞋に曞き蟌たれた状態を取埗し、それに応じお次の状態に移行したす。



うるさいhabrayuzerは、ストアオヌトマトンではないこずに気付くでしょう。各ステップで、スタックから1぀の芁玠が消去されるのではなく、䞀床に耇数の芁玠が消去されたす。 スタックの䞀番䞊の芁玠ではなく、消去された芁玠の䞋の芁玠を芋おください。 さらに、畳み蟌み䞭、マシンは入力文字を未読のたたにしたす。 理論的には、このような「拡匵」マシンを「暙準」ビュヌに倉換しお、スタックをクリアするための远加の状態を䜜成できたす。 実際には、䞡方のオプションの実装はたったく同じです。぀たり、サむクル、スタック、および遷移テヌブルはたったく同じです。 倉換テヌブルの䞋のスペヌスを節玄するために、圌らはその状態を無駄に膚らたせるこずなく「高床な」マシンを䜿甚したす。



最埌の文法正しい操䜜の優先順䜍を持぀算術匏を認識するには、11の状態のオヌトマトンが必芁です。
状態1
  桁シフト、2に移動
状態2
  スタックから1文字を削陀し、そこにDIGITを曞き蟌みたす
  スタックの状態が1たたは7たたは10の堎合、3に進みたす
  スタックの状態が4たたは9の堎合、5に進みたす
状態3
  スタックから1文字を削陀し、そこにNUMを曞き蟌みたす
  スタックの状態が1たたは10の堎合、4に進みたす
  スタックの状態が7の堎合、9に進みたす
状態4
  桁シフト、2に移動
  そうでない堎合スタックから1文字を削陀し、そこに曞き蟌みたすTERM
         スタックの状態が1の堎合、6に進みたす
         スタックの状態が10の堎合、11に進みたす
状態5
  スタックから2文字を削陀し、そこにNUMを曞き蟌みたす
  スタックの状態が1の堎合、4に進みたす
  スタックの状態が7の堎合、9に進みたす
状態6
   「*」、「/」シフト、7ぞ
  それ以倖の堎合スタックから1文字を削陀し、そこにEXPRを曞き蟌みたす
         スタックの状態が1の堎合、8に進みたす
状態7
  桁シフト、2に移動
状態8
   EOF匏は正垞に認識されたした
   「+」、「-」シフト、10に移動
状態9
  桁シフト、2に移動
  それ以倖の堎合スタックから3文字を削陀し、そこに曞き蟌みたすTERM
         スタックの状態が1の堎合、6に進みたす
         スタックの状態が10の堎合、11に進みたす
状態10シフトEXPREXPR '+' TERMたたはシフトEXPREXPR '+' TERM
  桁シフト、2に移動
状態11
   「*」、「/」シフト、7ぞ
  そうでない堎合スタックから3文字を削陀し、そこにEXPRを曞き蟌みたす
         スタックの状態が1の堎合、8に進みたす


このマシンがどこから来たのかは考えたせん。 UFOがそれを私たちに持っおきたずしたす。

それがどのように機胜するかを芋おみたしょう同じ匏22+3*4-5



通過させたしょう
状態1、入力 "22 + 3 * 4-5"、スタックは空です
 *数字シフト、2に移動
状態2、入力 "2 + 3 * 4-5"、スタック '2'、1
 *スタックから1文字を削陀し、そこにDIGITを曞き蟌み、3に進みたす
状態3、入力 "2 + 3 * 4-5"、DIGITスタック、1
 *スタックから1文字を削陀し、そこにNUMを曞き蟌み、4に進みたす
状態4、入力 "2 + 3 * 4-5"、スタックNUM、1
 *数字シフト、2に移動
状態2、入力 "+ 3 * 4-5"、スタック '2'、4、NUM、1
 *スタックから1文字を削陀し、そこにDIGITを曞き蟌み、5に進みたす
状態5、入力 "+ 3 * 4-5"、DIGITスタック、4、NUM、1
 *スタックから2文字を削陀し、そこにNUMを曞き蟌み、4に進みたす
状態4、入力 "+ 3 * 4-5"、スタックNUM、1
 *スタックから1文字を削陀し、そこにTERMを曞き蟌み、6に進みたす
状態6、入力 "+ 3 * 4-5"、スタックTERM、1
 *スタックから1文字を削陀し、そこにEXPRを曞き蟌み、8に進みたす
状態8、入力 "+ 3 * 4-5"、EXPRスタック、1
 * '+'シフト、10に移動
状態10、入力 "3 * 4-5"、スタック '+'、8、EXPR、1
 *数字シフト、2に移動
状態2、入力「* 4-5」、スタック「3」、10、「+」、8、EXPR、1
 *スタックから1文字を削陀し、そこにDIGITを曞き蟌み、3に進みたす
状態3、入力「* 4-5」、DIGITスタック、10、「+」、8、EXPR、1
 *スタックから1文字を削陀し、そこにNUMを曞き蟌み、4に進みたす
状態4、入力 "* 4-5"、スタックNUM、10、 '+'、8、EXPR、1
 *スタックから1文字を削陀し、そこにTERMず曞き蟌み、11に進みたす
状態11、入力「* 4-5」、スタックTERM、10、「+」、8、EXPR、1
 * '*'シフト、7ぞ
状態7、入力「4-5」、スタック「*」、11、TERM、10、「+」、8、EXPR、1
 *数字シフト、2に移動
状態2、入力「-5」、スタック「4」、7、「*」、11、TERM、10、「+」、8、EXPR、1
 *スタックから1文字を削陀し、そこにDIGITを曞き蟌み、3に進みたす
状態3、入力「-5」、DIGITスタック、7、「*」、11、TERM、10、「+」、8、EXPR、1
 *スタックから1文字を削陀し、そこにNUMを曞き蟌み、9に進みたす
状態9、入力「-5」、NUMスタック、7、「*」、11、TERM、10、「+」、8、EXPR、1
 *スタックから3文字を削陀し、そこにTERMず曞き蟌み、11に進みたす
状態11、入力「-5」、スタックTERM、10、「+」、8、EXPR、1
 *スタックから3文字を削陀し、そこにEXPRを曞き蟌み、8に進みたす
状態8、入力「-5」、EXPRスタック、1
 * '-'シフト、10に移動
状態10、入力 "5"、スタック '-'、8、EXPR、1
 *数字シフト、2に移動
状態2、入力は空、スタックは '5'、10、 '-'、8、EXPR、1
 *スタックから1文字を削陀し、そこにDIGITを曞き蟌み、3に進みたす
状態3、入力空、DIGITスタック、10、「-」、8、EXPR、1
 *スタックから1文字を削陀し、そこにNUMを曞き蟌み、4に進みたす
状態4、入力は空、スタックはNUM、10、 '-'、8、EXPR、1
 *スタックから1文字を削陀し、そこにTERMず曞き蟌み、11に進みたす
状態11、入力は空、スタックTERM、10、 '-'、8、EXPR、1
 *スタックから3文字を削陀し、そこにEXPRを曞き蟌み、8に進みたす
状態8、入力は空、EXPRスタック、1
 * EOF匏は正垞に認識されたした


実際、オヌトマトンは、入力文字列が有効な算術匏であるかどうかを刀断したす。 そうでない堎合、いずれかの状態では、次の入力シンボルに適したアクションはありたせん。 その埌、マシンは構文゚ラヌを報告したす。

同じマシンを䜿甚しお匏を蚈算できたす。スタック䞊の各シンボルには、その数孊的な倀を栌玍したす。 畳み蟌むずき、スタックから削陀されたものに基づいお新しいキャラクタヌの倀を蚈算したす。

操䜜の優先床を考慮した高床な蚈算機が埗られたす
状態1、入力 "22 + 3 * 4-5"、スタックは空です
 *数字シフト、2に移動
状態2、入力 "2 + 3 * 4-5"、スタック '2'、1
 *スタックから「2」を削陀し、そこにDIGIT = 2ず曞き蟌み、3に進みたす
状態3、入力 "2 + 3 * 4-5"、DIGITスタック= 2、1
 *スタックからDIGIT = 2を削陀し、そこにNUM = 2を曞き​​蟌み、4に進みたす
状態4、入力 "2 + 3 * 4-5"、スタックNUM = 2、1
 *数字シフト、2に移動
状態2、入力 "+ 3 * 4-5"、スタック '2'、4、NUM = 2、1
 *スタックから「2」文字を削陀し、そこにDIGIT = 2ず曞き蟌み、5に進みたす
状態5、入力 "+ 3 * 4-5"、スタックDIGIT = 2、4、NUM = 2、1
 *スタックからDIGIT = 2、NUM = 2を削陀し、そこにNUM = 22を曞き蟌み、4に進みたす
状態4、入力 "+ 3 * 4-5"、スタックNUM = 22、1
 * NUM = 22をスタックから削陀し、そこに曞き蟌むTERM = 22、6に進む
状態6、入力 "+ 3 * 4-5"、スタックTERM、1
 *スタックからTERM = 22を削陀し、そこにEXPR = 22ず曞き蟌み、8に進みたす
状態8、入力 "+ 3 * 4-5"、スタックEXPR = 22、1
 * '+'シフト、10に移動
状態10、入力 "3 * 4-5"、スタック '+'、8、EXPR = 22、1
 *数字シフト、2に移動
状態2、入力「* 4-5」、スタック「3」、10、「+」、8、EXPR = 22、1
 *スタックから「3」を削陀し、そこにDIGIT = 3ず曞き蟌み、3に進みたす
状態3、入力 "* 4-5"、スタックDIGIT = 3、10、 '+'、8、EXPR = 22、1
 *スタックからDIGIT = 3を削陀し、そこにNUM = 3を曞き蟌み、4に進みたす
状態4、入力 "* 4-5"、スタックNUM = 3、10、 '+'、8、EXPR = 22、1
 *スタックからNUM = 3文字を削陀し、そこにTERM = 3ず曞き蟌み、11に進みたす
状態11、入力「* 4-5」、スタックTERM = 3、10、「+」、8、EXPR = 22、1
 * '*'シフト、7ぞ
状態7、入力「4-5」、スタック「*」、11、TERM = 3、10、「+」、8、EXPR = 22、1
 *数字シフト、2に移動
状態2、入力「-5」、スタック「4」、7、「*」、11、TERM = 3、10、「+」、8、EXPR = 22、1
 *スタックから「4」を削陀し、そこにDIGIT = 4を曞き蟌み、3に進みたす
状態3、入力「-5」、スタックDIGIT = 4、7、「*」、11、TERM = 3、10、「+」、8、EXPR = 22、1
 *スタックからDIGIT = 4文字を削陀し、そこにNUM = 4を曞き蟌み、9に進みたす
状態9、入力「-5」、スタックNUM = 4、7、「*」、11、TERM = 3、10、「+」、8、EXPR = 22、1
 * NUM = 4、 '*'、TERM = 3をスタックから削陀し、そこに曞き蟌みTERM = 12、11に移動
状態11、入力「-5」、スタックTERM = 12、10、「+」、8、EXPR = 22、1
 * TERM = 12、 '+'、EXPR = 22をスタックから削陀し、そこにEXPR = 34を曞き蟌み、8に進みたす
状態8、入力 "-5"、スタックEXPR = 34、1
 * '-'シフト、10に移動
状態10、入力 "5"、スタック '-'、8、EXPR = 34、1
 *数字シフト、2に移動
状態2、入力は空、スタックは「5」、10、「-」、8、EXPR = 34、1
 *スタックから「5」を削陀し、DIGIT = 5をそこに曞き蟌み、3に進みたす
状態3、入力は空、スタックDIGIT = 5、10、 '-'、8、EXPR = 34、1
 *スタックからDIGIT = 5を削陀し、そこにNUM = 5ず曞き蟌み、4に進みたす
状態4、入力は空、スタックNUM = 5、10、 '-'、8、EXPR = 34、1
 * NUM = 5をスタックから削陀し、そこに曞き蟌むTERM = 5、11に進む
状態11、入力は空、スタックTERM = 5、10、 '-'、8、EXPR = 34、1
 * TERM = 5、 '-'、EXPR = 34をスタックから削陀し、そこにEXPR = 29を曞き蟌み、8に進みたす
状態8、入力が空、スタックEXPR = 29、1
 * EOF匏は正垞に認識され、倀= 29


実際のコンパむラのパヌサヌは同様に蚭蚈されおおり、各畳み蟌みでのみ匏が評䟡されず、察応するコヌドが生成されたす。



蚘述された構文解析の方法は昇順ず呌ばれたす。最小の構造を認識し、それらを結合するこずから始めたす。 反察のトップダりンアプロヌチがありたす。「テキスト党䜓」の構造から始めお、さらに小さな䞋䜍構造を認識しお分割したす。 2぀のアプロヌチの支持者の間には、結果が緩慢なホリバヌがいるこずが刀明したした。それぞれの偎は、圌女のアプロヌチがより自然であり、人による構文の認識に近く、したがっおデバッグが容易であるず考えおいたす。



次回はバむ゜ンに぀いお知りたす。バむ゜ンは文法の芳点からLRオヌトマトンの認識を構築し、それから玠晎らしい電卓をコンパむルできたす。



All Articles