Cfor .NETパヌト2 +ボヌナスでクヌルな教育蚀語のコンパむラを開発しおいたす

こんにちは、Habrahabr



はじめに



この蚘事では、玄束したずおり、 この蚘事で始たったCool蚀語甚のコンパむラヌの開発の説明を続けたす。



颚氎での線集プロセスにはいく぀かの段階が含たれおいるこずを思い出させおください。これらの段階は䞋の図に瀺されおいたす。 コンパむラには3぀のステヌゞのみが含たれおおり、それらは右偎の同じ図に瀺されおいたす。











字句解析噚および構文解析噚は、最初の蚘事で蚀及されたした。



セマンティックアナラむザヌの䞻なタスクは、゜ヌスプログラムで蚀語の定矩ずのセマンティクスの敎合性をチェックするこずです。 これは䞻に型チェック 、぀たり コンパむラが、各挔算子に適切なタむプのオペランドがあるかどうかを確認するずき。



゜ヌスコヌドの䞭間衚珟を生成するには、䞭間コヌド生成が必芁です。䞭間衚珟は、 簡単に生成され、タヌゲットマシン蚀語に簡単に倉換される必芁がありたす 。 このような衚珟ずしお、たずえば、 3぀のアドレスコヌドが䜿甚されたす。



マシンに䟝存しないコヌド最適化のフェヌズは、䞭間コヌドを改善するために䜿甚されたすより速く、よりたれに、より短い。



コヌド生成ずは、䞭間衚珟をアセンブラヌたたは仮想マシンの䞀連の呜什に盎接倉換するこずです。



マシン䟝存の最適化フェヌズは、コヌドを最適化するためにタヌゲットマシンたずえばSSE からの特別な呜什を䜿甚するこずを陀いお、 マシンに䟝存しない最適化に䌌おいたす。 私たちの堎合、これらの責任はCLRによっお匕き受けられるこずは明らかです。



図からわかるように、1぀の段階で、巊偎の図から最倧3぀の段階を組み合わせたした。 これは、 System.Reflection.Emitツヌルを䜿甚しお䞭間コヌドを生成できないこず倉曎できないCIL呜什のシヌケンスが生成されるため、および党䜓ずしおの考えの悪いアヌキテクチャによっお説明されおいたす。



建築



うわヌ、どこから始めればいいのかわかりたせん

コヌドゞェネレヌタヌの手順を説明したす。

  1. クラス定矩
  2. 関数ずフィヌルドの定矩
  3. コンストラクタヌず関数コヌドの生成


クラス定矩


クヌルな゜ヌスコヌドはクラスのコレクションであるこずが知られおいたす。 圓然、 ゚ントリポむントが存圚する必芁がありたす。存圚しない堎合、䜕も実行されたせん。

したがっお、゚ントリ関数はMainクラスのメむン関数です。 クラスず関数の䞡方を手動で登録する必芁がありたす。 しかし、これに぀いおは埌で詳しく説明したす。



System.Reflection.Emitには、動的アセンブリの構築ずCILコヌドの生成に䜿甚される特別なクラスAssemblyBuilderずModuleBuilderがありたす。

クラスの説明を宣蚀するには、メ゜ッドを䜿甚したす

TypeBuilder ModuleBuilder.DefineType(string className, TypeAttributes attr, Type parent)
      
      





classNameはクラスの名前、 attrはその属性、 parentは芪ある堎合です。

TypeBuilderは動的な型で、コヌドを生成するずきに䜿甚されたすたずえば、new挔算子甚。



そのため、この段階では、䞋図に瀺すように、パヌサヌから取埗した構文ツリヌでクラスタむプのノヌドがバむパスされ、゜ヌスコヌド内のすべおのクラスが䞊蚘の方法を䜿甚しお決定されたす。



蚀語のオプションの文字は黄色で衚瀺されたす芪クラスの名前です。芪がない堎合、クラスはObjectを継承したす。



この段階では、クラス定矩のみが䜜成され、その䞭の関数ずフィヌルドの説明はありたせん。 関数ずフィヌルドをすぐに説明するず、クラスが定矩されおいないずいう゚ラヌが発生する堎合がありたすが、それに぀いおは埌で説明したす。



たた、クラスを定矩する前に、゜ヌスコヌド内の説明を正しい順序で䞊べ替えるこずをお勧めしたすたずえば、Aを継承するクラスBの説明があり、次にクラスAの説明がありたす。 しかし、残念ながらこれは実装されおいないため、すべおのクラスは䜿甚される順序で蚘述する必芁がありたす。



したがっお、この段階で蟞曞が受信されたす

 Dictionary<string, TypeBuilder> ClassBuilders_;
      
      





ここで、キヌはクラスの名前であり、倀はそのビルダヌです。



結論ずしお、すべおのコヌドを生成した埌、CreateTypeメ゜ッドを䜿甚しお動的型を確定する必芁がありたすこれはFinalAllClasses関数で行われたす。



関数ずフィヌルドの定矩


クラスを定矩した埌、各クラスで、さらに䜿甚するためにその関数ずメ゜ッドを決定する必芁がありたす。 これはメ゜ッドを䜿甚しお行われたす。

 public FieldBuilder DefineField(string fieldName, Type type, FieldAttributes attributes)
      
      





そしお

 public MethodBuilder DefineMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes);
      
      





それに応じお。



この段階の終わりに、二次元の蟞曞がいっぱいになりたす

 protected Dictionary<string, Dictionary<string, FieldObjectDef>> Fields_; protected Dictionary<string, Dictionary<string, MethodDef>> Functions_;
      
      







最初の次元の蟞曞キヌはクラスの名前で、2番目は関数たたはフィヌルドの名前です。 倀はそれぞれ関数蚘述子たたはフィヌルドですこれらのクラスに぀いおは埌ほど説明したす。



゜ヌスコヌド内の関数ずフィヌルドの説明を䞊べ替える問題は、クラスを定矩するずきのように、ここにはありたせん。 クラス定矩の段階で、他のクラスに関する情報が遺䌝を決定するために䜿甚され、DefineType関数で盎接䜿甚されるためです。 ただし、関数を定矩するために他の関数に関する情報は必芁ないためここではコヌド生成は行われたせん、他の関数ぞのリンクは必芁ありたせん。 これは、関数ずフィヌルドの定矩を任意の順序で生成できるこずを意味したす。



コンストラクタヌず関数コヌドの生成


そしお、ここで最も興味深いこずになりたした。 ここでは、すべおのクラスの関数本䜓ずコンストラクタヌの盎接再垰的なトラバヌサルが発生したす。



したがっお、前の段階から、すべおのクラスのすべおのメ゜ッド蚘述子MethodBuilderの蟞曞が取埗されたした。

メ゜ッドにCILステヌトメントを远加するには、最初に䜿甚しお特別なILGeneratorオブゞェクトを取埗する必芁がありたす

var ilGenerator = methodBuilder.GetILGenerator()



、このゞェネレヌタヌでEmitメ゜ッドを䜿甚したす。

Emitメ゜ッドには倚くの圢匏がありたす。

 void Emit(OpCode opcode); void Emit(OpCode opcode, int arg); void Emit(OpCode opcode, double arg); void Emit(OpCode opcode, ConstructorInfo con); void Emit(OpCode opcode, LocalBuilder local); void Emit(OpCode opcode, FieldInfo field); void Emit(OpCode opcode, MethodInfo meth); void Emit(OpCode opcode, Type cls);
      
      





OpCodeは、仮想.NETマシン呜什です。 説明付きの適切な手順のリストをここに瀺したす 。

そしお、2番目の匕数垞に存圚するずは限りたせんは、前の2぀の段階で取埗されたクラスたたはメ゜ッドの「ビルダヌ」たたは蚘述子です。



珟圚の関数ず珟圚のクラスは、それぞれ、コヌドが珟圚生成されおいる関数ずクラスです構文ツリヌを走査するずき。



最初に、関数匕数、ロヌカル倉数、䞀時ロヌカル倉数、およびクラスフィヌルドを蚘述するためにコヌドゞェネレヌタヌで導入したクラスに぀いお説明したす。 基本クラスはObjectDefであり、察応するオブゞェクトをロヌドおよびリリヌスする抜象メ゜ッドLoad、Removeが含たれたす。



お気づきかもしれたせんが、Coolでは、すべおの結果は衚珟です。 たた、各コンストラクタヌず各関数内には、 exprが 1぀だけありたす。 これがコヌドゞェネレヌタヌの䞻芁なポむントであり、この構造を凊理するためにEmitExpressionITree expressionNode関数が導入されたした。 コヌドは次のずおりです䞀郚の郚分をマヌク付きの楕円に眮き換えお省略したした。



 ObjectDef result; switch (expressionNode.Type) { case CoolGrammarLexer.ASSIGN: result = EmitAssignOperation(expressionNode); break; //  ... case CoolGrammarLexer.EQUAL: result = EmitEqualOperation(expressionNode); break; case CoolGrammarLexer.PLUS: case CoolGrammarLexer.MINUS: case CoolGrammarLexer.MULT: case CoolGrammarLexer.DIV: result = EmitArithmeticOperation(expressionNode); break; //... case CoolGrammarLexer.Term: if (expressionNode.ChildCount == 1) result = EmitExpression(expressionNode.GetChild(0)); else result = EmitExplicitInvoke(expressionNode); break; case CoolGrammarLexer.ImplicitInvoke: result = EmitInplicitInvoke(expressionNode); break; case CoolGrammarLexer.IF: result = EmitIfBranch(expressionNode); break; case CoolGrammarLexer.Exprs: for (int i = 0; i < expressionNode.ChildCount - 1; i++) { var objectDef = EmitExpression(expressionNode.GetChild(i)); objectDef.Remove(); } result = EmitExpression(expressionNode.GetChild(expressionNode.ChildCount - 1)); break; //... case CoolGrammarLexer.INTEGER: result = EmitInteger(expressionNode); break; } return result;
      
      





ご芧のずおり、ツリヌノヌドexpressionNodeのタむプに応じお、この挔算子の呜什を生成する長いケヌスから関数が呌び出されたす。



生成された関数で結果を返すには、匏コヌドの生成埌に単玔なOpCodes.Ret呜什を䜿甚したす関数がMainなどの䜕も返さない堎合、スタックがオヌバヌフロヌしないように、Retの前にOpCodes.Popを远加したす。



゚ントリポむントを決定するには、 AssemblyBuilderで定矩されおいるSetEntryPointメ゜ッドMethodInfo entryMethod が䜿甚されたす。 たた、 STAThreadAttribute属性は、アプリケヌションが単䞀のスレッドで実行されおいるこずを瀺す゚ントリポむントメ゜ッドに蚭定する必芁がありたす。 関数ず゚ントリポむントを定矩するコヌドは、DefineFunctionにありたす。



質問 これらのような構造のコヌドを生成する方法

math数孊←新しい数孊。 䜕らかの匏のフィヌルドを割り圓おる、ここでは新しい数孊。



回答 たず最初に、Cコンパむラヌ、したがっおコンパむラヌがその堎で蚈算を生成しないこずを理解する必芁がありたす-これは䞍可胜です。 ぀たり 右偎の匏はデフォルトのコンストラクタヌで評䟡されるず蚀いたいです。

そしお、匏コヌドここでは新しい数孊が生成された埌、呜什OpCodes.StfldたたはOpCodes.Stsfldが 、それぞれ非静的フィヌルドおよび静的フィヌルドのこのコンストラクタヌの本䜓に远加されたす。



いく぀かのCIL呜什ず蚭蚈の説明



CILはスタック蚀語です。぀たり、すべおの操䜜はスタックを䜿甚しお実行されたす。 たずえば、Mathクラスからフィボナッチ数を蚈算する関数呌び出しは、次のように゚ンコヌドされたす。



 ldsfld class Math Main::math ldsfld int32 Main::i callvirt instance int32 Math::fibonacci(int32) stloc.0
      
      





ここでは、最初に数孊むンスタンスハンドルがスタックにロヌドされ、次に枡されたint型の匕数がロヌドされたす。 その埌、 OpCodes.callvirt呜什を䜿甚しおfibonacci関数が呌び出されたすクラスの内郚関数を呌び出すずきに通垞のOpCodes.call呜什が䜿甚されるため、クラス蚘述子を枡す必芁はありたせん。 最埌のstloc.0ステヌトメントは、戻り倀をロヌカル倉数の番号0に栌玍したす。

さお、䞊蚘に埓っお、関数の最初の匕数は、明瀺的な圢匏の匕数がなくおも、呌び出されるクラスのむンスタンスthisぞのポむンタヌであるこずに泚意しおください。



CILのより詳现な説明は、たずえば、 Wikipediaにありたす。

、しかしReflection.Emitを䜿甚しおいく぀かの構文構造をコヌディングする方法を説明した方が良いでしょう。



算術挔算ず比范挔算


これらの操䜜は単玔に゚ンコヌドされたす-最初にスタックにプッシュされたす

オペランド、次にオペレヌションコヌド算術挔算の堎合、これらはOpCodes.Add、OpCodes.Sub、OpCodes.Mul、OpCodes.Divであり、比范挔算の堎合、 OpCodes.Ceq、OpCodes.Clt、OpCodes.Cgtです。



CILには、「以䞋」たたは「以䞊」の比范のための呜什がないため、このような比范を生成するために、1぀ではなく3぀の呜什が䜿甚されたすここで、「<=」は「not>」ず同等です。



 OpCodes.Cgt OpCodes.Ldc_I4_0 OpCodes.Ceq
      
      





OpCodes.Ceqは、スタック䞊の2぀の芁玠を比范し、等しい堎合は1を返し、等しくない堎合は0を返したす。



構築する堎合


算術挔算のコヌディングず比范するず、この呜什のコヌディングには困難がありたす。これは、条件付きゞャンプず無条件ゞャンプのラベルに䜕らかの方法でラベルを付ける必芁があるずいう事実にありたす。 ただし、これは簡単に行えたす。 DefineLabelメ゜ッドを䜿甚しお、ILGeneratorでラベルを䜜成したす。その埌、Labelメ゜ッドを䜿甚しお、MarkLabelメ゜ッドを䜿甚しおコヌドをマヌクする必芁がありたす。 これらのラベルは、条件付きおよび無条件の分岐呜什を゚ンコヌドするために䜿甚されたす。 したがっお、 OpCodes.Brfalseは、スタックの最䞊郚の倀がれロに等しいずきに発生する条件付き遷移です。 OpCodes.Brは無条件の移行です。 明確にするために、コヌドを瀺したした。



 protected ObjectDef EmitIfBranch(ITree expressionNode) { var checkObjectDef = EmitExpression(expressionNode.GetChild(0)); checkObjectDef.Load(); checkObjectDef.Remove(); var exitLabel = CurrentILGenerator_.DefineLabel(); var elseLabel = CurrentILGenerator_.DefineLabel(); CurrentILGenerator_.Emit(OpCodes.Brfalse, elseLabel); var ifObjectDef = EmitExpression(expressionNode.GetChild(1)); ifObjectDef.Load(); ifObjectDef.Remove(); CurrentILGenerator_.Emit(OpCodes.Br, exitLabel); CurrentILGenerator_.MarkLabel(elseLabel); var elseObjectDef = EmitExpression(expressionNode.GetChild(2)); elseObjectDef.Load(); elseObjectDef.Remove(); CurrentILGenerator_.MarkLabel(exitLabel); return LocalObjectDef.AllocateLocal(GetMostNearestAncestor(ifObjectDef.Type, elseObjectDef.Type)); }
      
      





構築しながら


この蚭蚈はIfによく䌌おいたす。 このデザむンの本䜓の䞭で、垞にPopを実行する必芁があるこずを忘れないでください。 内郚匏が評䟡され、その結果は䜿甚されたせん。 Coolでは、このステヌトメントは垞にvoidを返したす。



挔算子「@」および「Case」


@挔算子は基本的にCコヌドの匏a as B.methodNameに䞀臎し、Caseステヌトメントは動的型チェックを䜿甚し、匏a is B in Cに䞀臎したす。

残念ながら、これらの挔算子は実装されおいたせん。

ただし、特定の型ぞのキャストはcastclass <class>ステヌトメントを䜿甚しお実装されおいるず蚀えたす メ゜ッドぞのキャストずメ゜ッドの呌び出しは、 constrainedを䜿甚しおすぐに実装されたす。<thisType> [prefix] 

たた、動的な型チェックはisinst <class>ステヌトメントを䜿甚しお実装されたす。



トヌクンID凊理


ツリヌノヌドタむプがIdタむプに察応する堎合、次のアクションが実行されたす EmitIdValue関数で。

  1. ロヌカル倉数での識別子怜玢芋぀からない堎合
  2. 関数の匕数で識別子を怜玢し、芋぀からない堎合は、
  3. 珟圚のクラスのフィヌルドで識別子を怜玢し、芋぀からない堎合は、
  4. Idが定矩されおいない゚ラヌを生成したす


このセクションでは、CIL呜什ず、耇雑であるず思われる構文構造のコヌド生成に぀いお説明したした。 他のすべおのCILの手順に぀いおは、Wikiペヌゞを参照できたす。このペヌゞぞのリンクは、トピックの最埌にありたす。 たた、゜ヌスコヌドでコヌド生成の詳现を確認できたす。



゚ラヌ凊理



コンパむラの゚ラヌは異なりたす 黒、癜、赀の 字句 、 構文 、 セマンティック 、および䞀般 。



゚ラヌ番号、コヌド内の䜍眮行ず列、゚ラヌの皮類、およびその説明を含む抜象クラスCompilerErrorがそれらすべおに察しお䜜成されたした。



字句゚ラヌず構文゚ラヌを制埡するこずは䞍可胜です少なくずもこのプロゞェクトでは、レクサヌずパヌサヌのレベルで゚ラヌから回埩するこずをANTLRで凊理したせんでした。 ここでは、䟋倖が単玔にキャッチされ、察応する゚ラヌむンスタンスが䜜成されたす。 これらはすべおCoolCompier.csファむルで確認できたす。



ただし、セマンティック゚ラヌのチェック䞻に型チェックは、「emit」のすべおの機胜に実装されおいたす。 型チェックは簡単な方法で実装されたす。 それにもかかわらず、このアプロヌチにより、1぀のパスで耇数のセマンティック゚ラヌの認識を実珟できたす。 以䞋に䟋を瀺したす算術挔算、゚ラヌが怜出された堎合、構文ツリヌは匕き続き走査したす

 protected ObjectDef EmitArithmeticOperation(ITree expressionNode) { var returnObject1 = EmitExpression(expressionNode.GetChild(0)); var returnObject2 = EmitExpression(expressionNode.GetChild(1)); if (returnObject1.Type != IntegerType || returnObject1.Type != returnObject2.Type) CompilerErrors.Add(new ArithmeticOperatorError( returnObject1.Type, returnObject2.Type, CompilerErrors.Count, expressionNode.Line, expressionNode.GetChild(1).CharPositionInLine, expressionNode.GetChild(0).CharPositionInLine)); ... }
      
      





たあ、䞀般的な皮類の゚ラヌには、「ファむルが別のプロセスでビゞヌです」、「゚ントリポむントが芋぀かりたせんでした」などの゚ラヌがありたす。それらに぀いお話すのは特に面癜くありたせん。



むンタヌフェヌス



構文の匷調衚瀺


私が蚀ったように、コヌドを操䜜するためのコンポヌネントずしお、WPFでAvalonEditを䜿甚したした 。



構文を匷調するために、拡匵子.xshdを持぀特別なファむルが䜿甚されたす。これは、さたざたな単語や芏則のフォントスタむルを蚘述しおいたす。



たずえば、コメントは次のように瀺されたす。

 <Span color="Comment" begin="--" /> <Span color="Comment" multiline="true" begin="\(\*" end="\*\)" />
      
      





このようなキヌワヌド

 <Color name="Keywords" foreground="Blue" /> ... <Keywords color="Keywords"> <Word>classWord> <Word>elseWord> <Word>falseWord> ... Keywords>
      
      







たた、どの文字シヌケンスが数字たたは文字列であるか、およびそれらを匷調衚瀺する方法を決定するために必芁なルヌルもありたす。

 <Rule foreground="DarkBlue"> \b0[xX][0-9a-fA-F]+ # hex number |\b ( \d+(\.[0-9]+)? #number with optional floating point | \.[0-9]+ #or just starting with floating point ) ([eE][+-]?[0-9]+)? # optional exponent Rule>
      
      







他のすべおの匷調衚瀺ルヌルは、ファむルCoolHighlighting.xshdにありたす。



折りたたみず自動補完


この゚ディタヌではブロックの折りたたみず展開が可胜で、 CoolFoldingStrategy.csに実装されおいたす 。 コヌドは私のものではないので、コメントするこずは控えたす。 圌のおかげで、䞭括匧の間にあるすべおのものを最小化たたは拡匵できるずしか蚀えたせん。 ルヌプにはこのような機䌚はないはずなので、これはあたり正しくないようです。



たた、このコンポヌネントを䜿甚するず自動補完を実行できたすが、コヌド生成に関係なくセマンティックツリヌを生成できる別のアヌキテクチャを最初から実行する必芁があったため、実行したせんでした。



最埌に、むンタヌフェむスの芳点から、芋぀かった゚ラヌをコヌド行に関連付ける方法に぀いお説明したす。 以䞋に瀺すコヌドでは、キャリッゞがスクロヌルされ、特定の゚ラヌが発生した堎所にキャリッゞが転送されたす。



 tbEditor.ScrollTo((int)compilerError.Line, (int)compilerError.ColumnStart); int offset = tbEditor.Document.GetOffset((int)compilerError.Line, (int)compilerError.ColumnStart); tbEditor.Select(offset, 0); tbEditor.Focus();
      
      





tbEditor-゚ディタヌコンポヌネントのむンスタンス。

compilerError-゚ラヌ説明は前のセクションにありたす;



そしおもちろん、このセクションは、コンパむラ自䜓のスクリヌンなしでは完党ではありたせん。







コヌド゚ディタは巊䞊にあり、ログず゚ラヌのリストは巊䞋にありたす。 右偎には、コヌドをコンパむルするためのボタンがありたすF5を抌しおコンパむルしお実行するこずも、F6を抌しおコンパむルするこずもできたす。

明確にするために、プログラムはトヌクンのリストず構文ツリヌ右偎を衚瀺したす。 トヌクンたたは構文構造をダブルクリックするず、キャリッゞがスクロヌルされ、キャリッゞが適切な堎所に移動したす。



さらなるアヌキテクチャの改善



珟圚の知識ず十分なモチベヌションで再びCool蚀語のコンパむラを曞き始めた堎合、おそらく2぀のコンパむル段階-セマンティックツリヌの構築ず3たたは4アドレスの䞭間コヌドの生成-を遞択するでしょう。



セマンティックツリヌは、既に述べたように、コヌド生成の前にリアルタむムでセマンティック゚ラヌの自動眮換ずチェックを実珟したす。



3アドレスの䞭間コヌドを䜿甚するず、珟圚のアプロヌチでは適甚できない最適化手法を適甚できたす。 たずえば、この皮のコマンドの畳み蟌みず他の最適化

stloc.0

ldloc.0






゜ヌスの説明ボヌナス



2011幎にMSTUで開催された「Designing Compilers」コヌスで持っおいたすべおのラボを、 コヌドごずのコレクションにたずめるこずにしたした。 N.E.バりマン11番目のオプション。 圌らは誰かに圹立぀ず思いたす。



すべおの実隓宀の説明

  1. タスク1.文法を分割したす。 このラボでは、文法分割アルゎリズムを実装しおいたす 。 手順の詳现な説明ず順序は、102ペヌゞの第2巻の教科曞「Aho A.、Ulman J.解析、翻蚳、およびコンパむルの理論」にありたす。 文法の文字。

    圓時はただLINQで遊んでいたこずを芚えおいたす。 したがっお、これらの関数のコヌドは、効率的で矎しいずはほど遠いものの、かなり短いこずが刀明したした。 :)



  2. タスク2.通垞の蚀語のチェヌンの認識。 ここでは、次のサブタスクが実装されおいたす。

    1. 通垞の係数を䜿甚した暙準システムの゜リュヌション。

      説明 正芏衚珟は巊偎の文法から䜜成する必芁がありたす。 ぀たり 通垞の係数SRSを䜿甚しおシステムを「解決」したす。 係数は終端であり、未知数は非終端です。

      たずえば、そのような文法の堎合



      Σ = {0, 1}

      N = {S, A, B}

      P = {S → 0∙A|1∙S|λ, A → 0∙B|1∙A, B → 0∙S|1∙B}

      S = S






      次の匏が刀明したす小さな゚ラヌがありたすが、ポむントはありたせん。



      S = 1*+1*∙0∙1*∙0∙1*∙0∙1*+1*∙0∙1*∙0∙(0∙1*∙0∙1*∙0)*∙0∙1*

      A = 1*∙0∙1*∙0∙1*+1*∙0∙(0∙1*∙0∙1*∙0)*∙0∙1*

      B = 1*∙0∙1*+(0∙1*∙0∙1*∙0)*∙0∙1*











      このラボで䜜業しおいるずき、代数「+」、「*」、「/」の通垞の操䜜を、正芏衚珟のコンテキストで察応する「or」、「concatenation」、「iteration」の操䜜にオヌバヌロヌドするこずで、SRKメ゜ッドを解くこずができるこずに気付きたしたガりス、通垞のSLAEを解決するずきも 唯䞀のこずは、最適化のために䜕かが倉曎されたこずです。



      ただし、これらの操䜜をオヌバヌロヌドするこずも重芁なタスクです。これらは数字ではありたせんが、ここの行ずルヌルは異なるためです連結する堎合、行を「接着」する必芁があり、「or」操䜜では同じ圢匏のたたにする必芁があり、れロは空のセットですØ単䜍はラムダλです。 したがっお、0たたは1による乗算たたは加算の堎合、これらの行を最適化する必芁もありたす。最適化しないず、すぐに「膚匵」したす。

    2. 正芏係数を䜿甚した暙準の連立方皋匏の解である正芏衚珟を䜿甚しお、NFA非決定性有限オヌトマトンを構築したす。
    3. NCAをシミュレヌトするこずを決定したした。 芁するに-これは修正された深さ怜玢です


  3. 問題3. Coca-Yanger-Kasamiアルゎリズム

    ここでは、Kok-Yanger-Kasamiアルゎリズムを䜿甚しお解析を実装する必芁がありたした



    このアルゎリズムでは、文法をChomskyの暙準圢匏で指定する必芁がありたすが、これはもちろん䞍䟿です。字句解析噚の欠劂も䞍䟿さを匕き起こすので、パヌサヌがそれらを認識するように、すべおのトヌクンはスペヌスで区切られなければなりたせん。



    この実習ラボの結果は、解析テヌブルず、入力された文字列が特定の文法に属するかどうかの実際の定矩です。



  4. タスク4.再垰降䞋の方法

    ここでは、再垰降䞋の方法を実装する必芁がありたした。同じ原則に぀いお、すべおのLL*コヌドゞェネレヌタヌたずえば、ANTLRはコヌドを生成したす。ここでのみ、すべおが手動で実装されたす。明確にするために、解析ツリヌもここに構築されたす。







  5. 5-8. Cool

    ---- Cool .NET, .



    , , Cool, , , :

    • Example1.cool — ( , , ).
    • BinaryTree.cool — , — (, , ).
  6. , ( .pdf):

    1. Evaluating Simple C Expressions — - .
    2. iFlop — iFlop .


䞀郚のラボでは、Microsoft.GLEEグラフのレンダリングに玠晎らしい、しかし閉鎖された有料のラむブラリを䜿甚しおいるこずに泚意しおください。この蚘事から刀断するず、このラむブラリではいく぀かの巧劙なアルゎリズムずヒュヌリスティックが䜿甚され、レンダリングされたグラフが人によっお描かれ、ノヌドサむズが最倧で最小の領域を占有しおいるように芋えたす。 ハブでほずんど誰も蚀及しおいないのは奇劙です。

利点は、このラむブラリの䜿甚が簡単なこずです。たずえば、ノヌド間の゚ッゞの远加は、゜ヌスが1぀のノヌドの名前で、タヌゲットが別のノヌドの名前である関数を䜿甚しお実行さEdge AddEdge(string source, string target)



れたす。

぀たりノヌド間に通信を远加するために、最初にノヌドを䜜成する必芁はありたせん。



関数を䜿甚Edge AddNode(string nodeId)





するず、Edgeオブゞェクトのむンスタンスが返され、属性テキストの色、ノヌドの色、むンデントなどを倉曎



できたすが、私は䜕を考えおも、私はMicrosoftのサポヌタヌではありたせん。 



すべおのスキヌムを䜜成および線集するには、䟿利なオンラむンサヌビスlucidchart.comを䜿甚したした。



文孊



私はこのトピックの著者に同意したす。このテヌマに関する倚くの本を読む必芁はありたせんが、1冊で十分ですが十分です。

コンパむラをお勧めしたす。Principles、Technologies and Tools、2008、Alfred W. Aho、Monica S. Lam、Ravi Seti、Jeffrey D. Ullman。

たた、私がよく䜿甚するCIL指瀺のリストぞのリンクも投皿したす。



GitHubプロゞェクト



それだけです



All Articles