مخطط تدفق التحكم

بعض الأمثلة على قواعد اللغة الخالية من السياق: (أ) جملة if-then-else (ب) حلقة while (ج) حلقة طبيعية ذات مخرجين، مثل حلقة while مع جملة if...break في المنتصف؛ غير مُهيكلة ولكنها قابلة للاختزال (د) قاعدة لغة خالية من السياق غير قابلة للاختزال: حلقة ذات نقطتي دخول، مثل الانتقال إلى حلقة while أو for
مخطط تدفق التحكم الذي يستخدمه مترجم لغة Rust لتنفيذ عملية توليد التعليمات البرمجية.

في علم الحاسوب ، يُعدّ مخطط تدفق التحكم ( CFG ) تمثيلاً ، باستخدام ترميز الرسم البياني ، لجميع المسارات التي يمكن اجتيازها عبر دالة أثناء تنفيذها ، أو ما يُعرف بتدفق التحكم . وقد ابتكرت فرانسيس إي. ألين مخطط تدفق التحكم ، [ 1 ] [ 2 ] حيث أشارت إلى أن ريس تي. بروسر استخدم مصفوفات الاتصال المنطقية لتحليل التدفق سابقًا. [ 3 ]

يُعد مخطط تدفق التحكم (CFG) أساسيًا للعديد من تحسينات المترجم وأدوات التحليل الثابت .

تعريف

مخطط تدفق التحكم هو الرسم البياني الموجه للكتل الأساسية للوظيفة (عقد الرسم البياني) وتدفق التحكم بينها (حواف الرسم البياني).

تختلف التفاصيل الدقيقة بين التمثيلات المختلفة. عادةً، تتكون الكتلة الأساسية من تسلسل خطي من التعليمات أو العبارات. ولا يمكن إلا للتعليمة أو العبارة الأخيرة في كل كتلة تنفيذ تدفق التحكم، ولا يمكن توجيه تدفق التحكم إلا إلى التعليمة أو العبارة الأولى في الكتلة.

في معظم تمثيلات قواعد اللغة الخالية من التحكم، يوجد قسمان مُخصصان: قسم الدخول ، الذي يدخل من خلاله التحكم إلى الدالة، وقسم الخروج ، الذي يخرج من خلاله التحكم بالكامل من الدالة (عادةً عن طريق العودة). [ 4 ] تسمح بعض التمثيلات بوجود أقسام خروج متعددة، خاصةً إذا كانت هناك أنواع مختلفة من الخروج، أو تسمح بحذف قسم الخروج إذا لم يكن الوصول إليه ممكنًا.

إذا كان هناك حافة تحكم في التدفق من الكتلة A إلى الكتلة B، فإن A تسمى سلفًا لـ B، وB تسمى خلفًا لـ A.

أمثلة

كمثال بسيط، انظر إلى تعريف الدالة التالية في لغة C :

void print_within_parentheses ( const char * p ) { printf ( "(" ); // 1 if ( p != NULL ) { // 1 printf ( "%s" , p ); // 2 } // 2 printf ( ")" ); // 3 }

تتكون هذه الوظيفة من ثلاثة أقسام أساسية:

  • الكتلة 1 هي كتلة الدخول. تمتد من بداية الدالة حتى نهاية التعبير . وتنتهي بتدفق التحكم، إما بالدخول إلى الكتلة 2 إذا كان الشرط صحيحًا أو بالانتقال مباشرةً إلى الكتلة 3 إذا كان الشرط خاطئًا.p != NULLif
  • الجزء الثاني هو صلب العبارة if. وينتهي بالانتقال بشكل غير مشروط إلى الجزء الثالث.
  • الكتلة الثالثة هي كتلة الخروج. وهي تمتد من نهاية العبارة ifإلى العبارة الضمنية returnفي نهاية جسم الدالة.

يُصعّب الهيكل المتداخل للبرنامج المصدر رؤية الكتل الأساسية. ولتمثيل بديل يجعل الكتل أكثر وضوحًا، يمكننا تبسيط هذا الهيكل إلى سلسلة من الكتل المُصنّفة. ولتوضيح مسار التحكم، سنشترط أن تنتهي كل كتلة إما بـ ` goto، أو بـ if`/` elseفي goto`s`، أو returnبـ `(فقط في كتلة الخروج).

void print_within_parentheses ( const char * p ) { block1 : { printf ( "(" ); if ( p != NULL ) { goto block2 ; } else { goto block3 ; } }block2 : { printf ( "%s " , p ); goto block3 ; }block3 : { printf ( ")" ); return ; } }

هذا تمثيل على مستوى المصدر لمخطط تدفق التحكم. تتكون الكتل الأساسية من تسلسلات من عبارات لغة C مأخوذة مباشرة من البرنامج المصدر. تم حذف تدفق التحكم المنظم فقط.

والآن، لننظر إلى مثال أكثر تعقيداً يتضمن حلقة تكرارية:

void print_as_ordered_tuple ( const char * const * p ) { printf ( "(" ); // 1 bool first = true ; // 1 for (; * p != NULL ; ++ p ) { // 2 if ( ! first ) { // 3 printf ( "," ); // 4 } // 4 first = false ; // 5 printf ( "%s" , * p ); // 5 } // 5 printf ( ")" ); // 6 }

تحتوي هذه الوظيفة على ستة كتل أساسية، والتي يمكن رؤيتها بوضوح في تمثيلنا على مستوى المصدر لـ CFG:

void print_as_ordered_tuple ( const char * p ) { bool first ;block1 : { printf ( "(" ); first = true ; goto block2 ; }block2 : { if ( * p != NULL ) { goto block3 ; } else { goto block6 ; } }block3 : { if ( ! first ) { goto block4 ; } else { goto block5 ; } }block4 : { printf ( "," ); goto block5 ; }block5 : { first = false ; printf ( "%s " , * p ); ++ p ; goto block2 ; }block6 : { printf ( ")" ); return ; } }

لا يُستخدم هذا النمط من تمثيل قواعد تدفق التحكم على مستوى العبارات بشكل شائع، وهو معروض هنا لأغراض التوضيح فقط. لا يمكن تمثيل جميع البرامج بهذه الطريقة بسهولة، حتى في لغة C. لاحظ كيف تم رفع تعريف المتغير المحلي إلى بداية الدالة، وكيف block1تم تحويل تهيئته إلى عملية إسناد. سيؤدي هذا إلى صعوبات في التعامل مع الميزات التي تعتمد على النطاق، مثل التظليل والمصفوفات ذات الأطوال المتغيرة. كما ستحتاج العبارات إلى إعادة كتابة كبيرة للتعامل مع تدفق التحكم على مستوى التعبير، كما هو الحال مع المعاملات &&و ||و .? :

تستخدم معظم تمثيلات قواعد التحكم في التدفق (CFG) العملية مكوناتٍ أخرى غير عبارات المصدر الكاملة كعناصر أساسية في كتلها. على سبيل المثال، تستخدم أطر عمل المترجمات مثل LLVM قواعد تحكم في التدفق تتكون كتلها الأساسية من تعليمات إسناد ثابتة مجردة أحادية كنموذج وسيط رئيسي. إليك الدالة المذكورة أعلاه مترجمةً إلى نموذج وسيط LLVM:

define void @print_as_ordered_tuple ( ptr %0 ) { block1: %p = alloca ptr %first = alloca i1 store ptr %0 , ptr %p call i32 ( ptr , ...) @printf ( ptr @"(" ) store i1 1 , ptr %first br label %block2block2: %1 = تحميل المؤشر ، المؤشر %p %2 = تحميل المؤشر ، المؤشر %1 %3 = icmp ne ptr %2 ، null br i1 %1 ، label %block3 ، label %block4block3: %4 = تحميل i1 ، مؤشر %first br i1 %4 ، تسمية %block4 ، تسمية %block5block4: call i32 ( ptr , ...) @printf ( ptr @"," ) br label %block5block5: store i1 0 , ptr %first %5 = load ptr , ptr %p %6 = load ptr , ptr %5 call i32 ( ptr , ...) @printf ( ptr @"%s" , ptr %6 ) %7 = load ptr , ptr %p %8 = getelementptr inbounds ptr , ptr %7 , i32 1 store ptr %8 , ptr %p br label %block2block6: call i32 ( ptr , ...) @printf ( ptr @")" ) ret void }

لاحظ كيف أن بنية الكتلة متطابقة في كل من مخططات تدفق التحكم على مستوى المصدر ومخططات تدفق التحكم في LLVM. في كلا التمثيلين، تتمتع الدوال بنفس الدلالات الأساسية، حيث تؤدي نفس تسلسل العمليات وتدفق التحكم. الاختلاف يكمن فقط في تمثيل العمليات الفردية.

بناء

يمكن الحصول على مخطط تدفق تحكم واضح للغاية من دالة مصدرية بوضع كل عبارة في كتلة أساسية خاصة بها. إذا لم تكن العبارة عبارة تحكم، تُضاف قفزة "انتقالية" إلى كتلة العبارة التالية. لسوء الحظ، يؤدي هذا عادةً إلى إنشاء عدد كبير من الكتل الأساسية والقفزات الانتقالية غير الضرورية، مما يجعل التحليل اللاحق أكثر تعقيدًا وتكلفة. من المستحسن عادةً وضع العبارات المتتالية في نفس الكتلة الأساسية كلما أمكن ذلك. بعبارة أخرى، يجب أن تتمتع كل حافة A→B في مخطط تدفق التحكم بالكامل بالخاصية التالية:

درجة الخروج (أ) > 1 أو درجة الدخول (ب) > 1 (أو كلاهما). [ 5 ]

يمكن اشتقاق مثل هذا الرسم البياني من مخطط تدفق التحكم ذي العبارة الواحدة لكل كتلة، وذلك بإجراء تقليص للحواف لكل حافة تُخالف الشرط المذكور أعلاه، أي بدمج كتلتين عندما تنتقل كتلة المصدر دائمًا إلى كتلة الوجهة، ولا يمكن الانتقال إلى كتلة الوجهة إلا من كتلة المصدر. مع ذلك، فإن هذه الخوارزمية القائمة على التقليص قليلة الأهمية العملية، باستثناء كونها وسيلة مساعدة بصرية لفهم بناء مخطط تدفق التحكم، نظرًا لتكلفة بناء الشكل الأولي. في التطبيقات النموذجية، يُبنى مخطط تدفق التحكم مباشرةً من البرنامج بطريقة تُقلل من الكتل غير الضرورية، مثل فحص البرنامج بحثًا عن الحدود الضرورية بين الكتل الأساسية . [ 5 ]

إمكانية الوصول

إمكانية الوصول هي خاصية بيانية مفيدة في التحسين. إذا تعذر الوصول إلى كتلة ما عبر أي مسار من كتلة الإدخال، فلا يمكن تنفيذها، وفي هذه الحالة تُسمى شيفرة غير قابلة للوصول . عادةً ما يمكن إزالة الشيفرة غير القابلة للوصول من مخطط تدفق التحكم دون أي عواقب سلبية.

إذا تعذّر الوصول إلى كتلة الخروج من كتلة الدخول عبر أي مسار، فلن يتمكن تدفق التحكم من مغادرة الرسم البياني بشكل طبيعي. يشير هذا إلى وجود حلقة لا نهائية ، أو في التمثيلات التي تدعم هذه الخصائص مباشرةً، إلى خروج غير طبيعي أو إنهاء غير طبيعي للبرنامج. لا يعني إمكانية الوصول إلى كتلة الخروج عبر مسار ما أن البرنامج سيصل إليها بالضرورة، ومن المستحيل إثبات الوصول إليها في رسم بياني عام؛ انظر مشكلة التوقف .

يمكن أن يكشف التحسين عن أجزاء من التعليمات البرمجية غير قابلة للتنفيذ وحلقات لا نهائية لم تكن ظاهرة في البرنامج الأصلي. على سبيل المثال، انظر إلى دالة LLVM التالية:

define void @double_until_odd ( ptr %p ) { block1: br label %block2block2: %0 = load i32 , ptr %p ; تحميل القيمة الحالية من %p %1 = mul i32 %0 , 2 ; ضرب الناتج في 2 store i32 %1 , ptr %p ; تخزين الناتج مرة أخرى في %p %2 = and i32 %1 , 1 ; إخفاء البت الأدنى من الناتج %3 = icmp eq i32 %2 , 0 ; التحقق مما إذا كان الناتج 0 br i1 %3 , label %block2 , label %block3 ; تكرار العملية إذا كان كذلكblock3: ret void }

بهذا الشكل، لا تُعدّ الحلقة في هذه الدالة حلقةً لا نهائية، لوجود مسارٍ يُخرجها: إذا %3كانت قيمة `x` خاطئة، فسينتقل البرنامج إلى هذا المسار block3ويعود. مع ذلك، يُمكن للتحليل العددي إثبات أن حاصل ضرب أي عدد في 2 هو عدد زوجي، ما يعني أن قيمة `x` %2تساوي صفرًا دائمًا، ولا %3يُمكن أن تكون خاطئة أبدًا. لذا، يُمكن تحسين هذه الدالة إلى الشكل التالي:

define void @double_until_odd ( ptr %p ) { block1: br label %block2block2: %0 = load i32 , ptr %p ; تحميل القيمة الحالية من %p %1 = mul i32 %0 , 2 ; ضربها في 2 store i32 %1 , ptr %p ; تخزين الناتج مرة أخرى في %p br label %block2block3: ; غير قابل للوصول ret void }

يوجد الآن حلقة لا نهائية في مخطط تدفق التحكم، ولم يعد بالإمكان الوصول إلى كتلة الخروج. تجدر الإشارة إلى أن هذا التحسين لم يغير سلوك البرنامج: فمن الثابت أن الحلقة لن تنتهي أبدًا. كل ما تغير هو أن مخطط تدفق التحكم يعكس هذه الحقيقة بدقة أكبر.

علاقات الهيمنة

تُهيمن الكتلة M على الكتلة N إذا كان كل مسار من المدخل إلى الكتلة N يمر أيضًا بالكتلة M. تُهيمن كتلة المدخل على جميع الكتل. يُقال إن M تُهيمن على N بشكلٍ صحيح إذا كانت M تُهيمن على N وكانتا كتلتين مختلفتين. علاوة على ذلك، يُقال إن عبارة أو تعليمة X تُهيمن بشكلٍ صحيح على عبارة أو تعليمة Y إذا كانت الكتلة التي تحتوي على X تُهيمن على الكتلة التي تحتوي على Y، وإذا كانتا نفس الكتلة، فإن X تسبق Y بشكلٍ صارم في الكتلة.

يُقال إن الكتلة M تهيمن مباشرة على الكتلة N إذا كانت M تهيمن على N، ولا توجد كتلة وسيطة P بحيث تهيمن M على P وتهيمن P على N. بعبارة أخرى، M هي الكتلة المهيمنة الأخيرة على جميع المسارات من المدخل إلى N. كل كتلة يمكن الوصول إليها لها كتلة مهيمنة مباشرة فريدة باستثناء كتلة المدخل، التي ليس لها كتلة مهيمنة مباشرة.

شجرة الهيمنة هي رسم بياني موجه يمثل علاقات الهيمنة في الدالة. تمثل عقد الرسم البياني الكتل الأساسية التي يمكن الوصول إليها في الدالة، ويوجد ضلع من الكتلة M إلى الكتلة N إذا كانت M مهيمنة مباشرة على N. بما أن لكل كتلة غير قابلة للوصول إليها مهيمنة مباشرة فريدة، فإن هذه الشجرة متجذرة عند كتلة الدخول. يمكن حساب شجرة الهيمنة بكفاءة باستخدام خوارزمية لينغاور-تارجان .

في الاتجاه المعاكس، يُقال إن الكتلة M تُهيمن على الكتلة N إذا كان كل مسار من N إلى المخرج يمر أيضًا بالكتلة M. (يُكتب هذا أحيانًا بدون واصلة : M تُهيمن على N). تُهيمن كتلة المخرج على جميع الكتل. يُقال إن M تُهيمن على N بشكل صحيح إذا كانت تُهيمن على N وكانتا كتلتين مختلفتين. تُعتبر M مُهيمنًا مباشرًا على N إذا كانت تُهيمن على N ولا توجد كتلة P بحيث تُهيمن M على P وتُهيمن P على N. كل كتلة يمكن الوصول منها إلى كتلة المخرج لها مُهيمن مباشر فريد باستثناء كتلة المخرج، التي ليس لها مُهيمن مباشر. ينتج عن هذا شجرة مُهيمنات ، جذرها كتلة المخرج، على الكتل التي يمكن الوصول منها إلى كتلة المخرج.

يشمل التعريف القياسي للهيمنة الكتل غير القابلة للوصول، بينما يشمل التعريف القياسي للهيمنة اللاحقة الكتل التي لا يمكن الوصول منها إلى كتلة الخروج. مع ذلك، تتميز هذه الكتل بخصائص فريدة في ظل هذه العلاقات: فالكتلة غير القابلة للوصول تهيمن عليها جميع الكتل، والكتلة التي لا يمكن الوصول منها إلى الخروج تهيمن عليها جميع الكتل لاحقًا. تتجاهل معظم التحليلات التي تعتمد على الهيمنة أو الهيمنة اللاحقة هذه الكتل، ولا تُدرج في أشجار الهيمنة أو الهيمنة اللاحقة. تتطلب بعض التمثيلات إضافة حواف مستحيلة لمنع وجود هذه الكتل، على الأقل من الناحية النظرية.

حواف خاصة

الحافة الحرجة هي الحافة التي لا تُعدّ الحافة الوحيدة الخارجة من كتلة المصدر، ولا الحافة الوحيدة الداخلة إلى كتلة الوجهة. تتطلب بعض التحسينات تقسيم الحواف الحرجة لإدراج تعليمات على طول الحافة دون التأثير على المسارات الأخرى في البرنامج. يتم تقسيم الحافة بإنشاء كتلة جديدة تحتوي فقط على قفزة إلى كتلة الوجهة، ثم استبدال وجهة التفرع الأصلية بالكتلة الجديدة.

الحافة المتراجعة هي حافة يوجد لها مسار بسيط من كتلة الدخول إلى كتلة المصدر (كما هو الحال عند البحث العميق في الرسم البياني) يشمل كتلة الوجهة. تشير الحافة المتراجعة إلى وجود حلقة في مخطط تدفق التحكم. تُسمى الحافة المتراجعة حافة خلفية إذا كانت كتلة الوجهة موجودة على جميع المسارات الممكنة إلى كتلة المصدر، أي إذا كانت كتلة الوجهة تهيمن على كتلة المصدر.

الحافة الشاذة هي حافة مجهولة الوجهة، ويمكن أن تنتجها بنيات معالجة الاستثناءات . وتميل هذه الحواف إلى إعاقة التحسين.

الحافة المستحيلة (المعروفة أيضًا بالحافة الوهمية ) هي حافة لا يمكن اجتيازها فعليًا أثناء التنفيذ، وتُضاف إلى الرسم البياني فقط للحفاظ على خاصية مفيدة. على سبيل المثال، تتطلب بعض التمثيلات إضافة حواف مستحيلة لضمان إمكانية الوصول دائمًا إلى كتلة الخروج، وأنها تُهيمن على جميع الكتل الأخرى.

مكونات مترابطة بقوة

المكون المتصل بقوة (SCC) في مخطط تدفق التحكم هو مجموعة من الكتل الأساسية التي يمكن الوصول إليها جميعًا من بعضها البعض. الكتل التي تشكل حلقةً ما تكون دائمًا جزءًا من نفس المكون المتصل بقوة. أما الكتلة التي لا تشكل حلقةً ما، فتكون دائمًا في مكون متصل بقوة خاص بها. وعلى وجه الخصوص، فإن كتلتي الدخول والخروج تشكلان دائمًا مكونات متصلة بقوة خاصة بهما.

تُشكّل المكونات المترابطة بقوة في مخطط تدفق التحكم (CFG) رسمًا بيانيًا موجهًا غير دوري يُسمى شجرة SCC ، حيث يكون للمكون A حافة إلى المكون B إذا كان أي جزء في A له حافة إلى أي جزء في B. وتكون شجرة SCC متماثلة مع مخطط تدفق التحكم إذا لم تكن هناك دورات في CFG؛ أما إذا وُجدت دورة، فإن شجرة SCC تُدمج جميع الأجزاء والحواف فيها في عقدة واحدة. وهذا مفيد للتحليلات التي ترغب في التعامل مع جميع الأجزاء في الدورة على أنها متكافئة. على سبيل المثال، عند محاولة إيجاد عمر كائن يغطي مجموعة من نقاط الاستخدام بأضيق نطاق ممكن، إذا كانت إحدى نقاط الاستخدام هذه تقع ضمن SCC دوري، فيجب أن يغطي العمر كل جزء في ذلك المكون بالكامل.

إدارة الحلقات

رأس الحلقة ( يُسمى أحيانًا نقطة دخول الحلقة) هو عنصر مهيمن يستهدفه الحافة الخلفية المُشكِّلة للحلقة. يهيمن رأس الحلقة على جميع الكتل في جسم الحلقة. قد تكون الكتلة رأس حلقة لأكثر من حلقة واحدة. قد تحتوي الحلقة على نقاط دخول متعددة، وفي هذه الحالة لا يكون لها "رأس حلقة".

لنفترض أن الكتلة M هي كتلة مهيمنة ذات عدة حواف واردة، بعضها حواف خلفية (أي أن M هي رأس حلقة). من المفيد لعدة مراحل تحسين تقسيم M إلى كتلتين: M pre و M loop . يتم نقل محتويات M والحواف الخلفية إلى M loop ، بينما يتم نقل باقي الحواف لتشير إلى M pre ، ويتم إدخال حافة جديدة من M pre إلى M loop (بحيث تصبح M pre هي الكتلة المهيمنة المباشرة لـ M loop ). في البداية، ستكون M pre فارغة، ولكن يمكن ملؤها بمراحل مثل نقل الكود الثابت داخل الحلقة . تُسمى M pre رأس ما قبل الحلقة ، بينما تُسمى M loop رأس الحلقة.

قابلية الاختزال

يُطلق على مخطط تدفق التحكم اسم "مخطط قابل للاختزال" إذا كانت جميع حوافه المتراجعة حوافًا خلفية. أما الحواف الأخرى في هذا المخطط فتُسمى حوافًا أمامية . [ 6 ] تُشكل الحواف الأمامية مخططًا موجهًا غير دوري ، بينما تؤدي الحواف الخلفية دائمًا إلى كتلة أساسية سبق أن مر بها تدفق التحكم. تتميز مخططات تدفق التحكم القابلة للاختزال عمومًا بخصائص ثابتة أقوى، ويمكن تحليلها وتحسينها بسهولة أكبر. على سبيل المثال، صُممت العديد من تحسينات الحلقات للعمل فقط على مخططات تدفق التحكم القابلة للاختزال.

غالبًا ما تُصمَّم لغات البرمجة الهيكلية بحيث تكون جميع مخططات التدفق الحر (CFGs) التي تُنتجها قابلة للاختزال، وتُنتج عبارات البرمجة الهيكلية الشائعة مثل IF وFOR وWHILE وBREAK وCONTINUE مخططات قابلة للاختزال بشكل موثوق. لإنتاج مخطط غير قابل للاختزال مباشرةً، نحتاج إلى عبارات مثل GOTO التي تسمح بالقفز إلى أي نقطة في البرنامج، مع العلم أن ليس كل استخدام لـ GOTO يُنتج مخططات تدفق حر غير قابلة للاختزال. كما يُمكن إنتاج مخططات تدفق حر غير قابلة للاختزال من خلال بعض تحسينات المُصرِّف، مثل تعدد الخيوط القفزية . يُمكن تحويل مخططات التدفق الحر غير القابلة للاختزال إلى مخططات تدفق حر قابلة للاختزال، ولكن هذا غالبًا ما يتطلب تكرار التعليمات البرمجية أو إضافة متغيرات جديدة إلى البرنامج.

ترابط الحلقة

تُحدد درجة ترابط الحلقات في مخطط تدفق التحكم (CFG) بالنسبة لشجرة بحث العمق أولاً (DFST) الخاصة بهذا المخطط. يجب أن تكون هذه الشجرة متجذرة عند عقدة البداية وأن تغطي جميع عقد مخطط تدفق التحكم.

في هذا السياق، تُسمى الحواف في مخطط السياق الحر التي تمتد من عقدة إلى أحد أسلافها في شجرة البحث ذات الصلة (بما في ذلك العقدة نفسها) بالحواف الخلفية. ولا يتطابق هذا بالضرورة مع التعريف المعتاد للحافة الخلفية، لأن سلف شجرة البحث ذات الصلة ليس بالضرورة أن يكون هو العقدة المصدر للحافة.

تُعرَّف ترابطية الحلقات بأنها أكبر عدد من الحواف الخلفية الموجودة في أي مسار خالٍ من الحلقات في مخطط التدفق الحر. في مخطط التدفق الحر القابل للاختزال، تكون ترابطية الحلقات مستقلة عن تحويل فورييه ذي المجال المختار. [ 7 ] [ 8 ]

تم استخدام اتصال الحلقة للتفكير في التعقيد الزمني لتحليل تدفق البيانات . [ 7 ]

مخطط تدفق التحكم بين الإجراءات

بينما تمثل مخططات تدفق التحكم تدفق التحكم لإجراء واحد، فإن مخططات تدفق التحكم بين الإجراءات تمثل تدفق التحكم لبرامج كاملة. [ 9 ]

انظر أيضاً

ملاحظات ومراجع

فهرس

وردت ملاحظة ببليوغرافية في كتاب التنين. [ 1 ]

  • "تحليل تدفق التحكم" (ملف PDF) . جامعة ولاية آيوا، قسم علوم الحاسوب. 2016. مؤرشف من النسخة الأصلية (ملف PDF) بتاريخ 19 ديسمبر 2016.
  • بروسر، ريس ت. (1959). "تطبيقات المصفوفات البوليانية في تحليل مخططات التدفق". أوراق بحثية قُدّمت في المؤتمر المشترك للحاسوب بين معهد مهندسي الراديو (IRE) ومعهد مهندسي الكهرباء والإلكترونيات (AIEE) ورابطة مكائن ​​الحوسبة (ACM) في الفترة من 1 إلى 3 ديسمبر 1959. الصفحات 133-138 . doi : 10.1145/1460299.1460314 . 
  • تار، بيري ل.؛ وولف، ألكسندر ل. (2011). هندسة البرمجيات: المساهمات المستمرة لليون ج. أوسترويل . سبرينغر ساينس آند بيزنس ميديا. ISBN 978-3-642-19823-6.
  • يوسفي، جواد (2015). "إخفاء أخطاء تدفق التحكم في الخلف الخاطئ باستخدام تكرار البيانات". المؤتمر الدولي الخامس لهندسة الحاسوب والمعرفة (ICCKE) لعام 2015. معهد مهندسي الكهرباء والإلكترونيات ( IEEE). الصفحات 201-205 . doi : 10.1109/ICCKE.2015.7365827 . ISBN  978-1-4673-9280-8.
أمثلة