Logo

ماركو كانتو:
أساسي باسكال

الفصل 5
التعليمات

إذا كانت أنواع البيانات هي إحدى أساسات البرمجة بباسكال، فإن التعليمات statments هي الأخرى كذلك. تعليمات اللغة البرمجية تُبنى على أساس كلمات مفتاحية keywords و مفردات أخرى تسمح لك بأن توجّه للبرنامج تتابع العمليات المطلوب انجازها. عادة ما يتم تضمين التعليمات داخل إجراءات procedures أو وظائف functions، كما سنرى في الفصل اللاحق. الآن سنركّز فقط على الأنواع الأساسية للأوامر التي يمكنك استخدامها لصنع برنامج.

التعليمات البسيطة والمركبة

تعليمة باسكال تكون بسيطة عندما لا تحتوي على أية تعليمات أخرى. كأمثلة على التعليمات البسيطة نجد تعليمات التخصيص assignment و استدعاءات الاجرائيات procedure calls. التعليمات البسيطة يتم الفصل بينها بفاصلة منقوطة semicolon :

X := Y + Z;  // assignment
Randomize;   // procedure call

عادة، تكون التعليمات جزءا من تعليمات مركّبة، مؤمّرة بعلامات البداية begin و النهاية end. التعليمة المركبة يمكن أن تظهر في مكان تعليمة باسكال عامة. ها هنا مثال:

begin
  A := B;
  C := A * 2;
end;

الفاصلة المنقوطة بعد آخر تعليمة قبل end ليست ضرورية. مثل التالي:

begin
  A := B;
  C := A * 2
end;

كلا النسختين صحيحتين. النسخة الأولى لها فاصلة منقوطة غير مجدية (لكنها لاتؤذي). هذه الفاصلة المنقوطة، في الواقع، هي تعليمة فارغة؛ تعليمة بدون توليف code . لا حظ هذا، أحيانا، التعليمات الفارغة يمكن استخدامها داخل الحلقات loops أو في حالات خاصة.

ملاحظة: بالرغم من أن الفاصلة المنقوطة الأخيرة لا تخدم أي غرض، إلا أنني أميل لإستخدامها مقترحا عليك القيام بنفس الأمر. أحيانا بعد كتابتك لبعض الأسطر ربما ترغب في إضافة تعليمة أخرى. فإذا كانت الفاصلة المنقوطة الأخيرة مفقودة فعليك أن تتذكّر اضافتها، لذا قد يكون من الأفضل اضافتها من المرة الأولى.

تعليمات التخصيص

التخصيصات assignments في باسكال تستخدم رمزي شارحة يساوي، ترميز غريب بالنسبة للمبرمجين الذين اعتادوا لغات اخرى. الرمز = و الذي يستعمل للتخصيص في بعض اللغات الأخرى، يستعمل في باسكال لاختبار المساواة equality.

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

التعليمات الشرطية

التعليمة الشرطية conditional statement تستعمل لتنفيذ إحدى التعليمات التي تتضمنها أو عدم تنفيذ و لا واحدة منها. بالاعتماد على شيء من الاختبار. يوجد شكلين من التعليمات الشرطية: تعليمات if و تعليمات case.

تعليمات If

تعليمة if يمكن استخدامها لتنفيذ تعليمة أخرى فقط إذا تحقق شرط معين (if-then)، أو للإختيار بين بديلين (if-then-else). يتم وصف الشرط بتعبير بولي boolean. مثال دلفي بسيط سيوضح كيفية كتابة تعليمات شرطية. أولا قم بإنشاء تطبيق application جديد، ثم ضع على النموذج form خانتي فحص check box و أربعة أزرار buttons . لا تغيّر أسماء الأزرار و خانات الفحص، قم بضغط مزدوج على كل زرّ لإضافة مناول handler للحدث OnClick الخاص بكل زرّ، ها هنا تعليمة if بسيطة للزر الأول:

procedure TForm1.Button1Click(Sender: TObject);
begin
  // simple if statement
  if CheckBox1.Checked then
    ShowMessage ('CheckBox1 is checked')
end;

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

الشكل 5.1: رسالة تعرض بواسطة مثال IfTest عندما تضغط على الزر الأول وتكون خانة الفحص الأول معلما.

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

procedure TForm1.Button2Click(Sender: TObject);
begin
  // if-then-else statement
  if CheckBox2.Checked then
    ShowMessage ('CheckBox2 is checked')
  else
    ShowMessage ('CheckBox2 is NOT checked');
end;

لاحظ أنه لايمكنك وضع فاصلة منقوطة بعد التعليمة الأولى و قبل مصطلح else، و إلا فإن المحوّل سيصدر خطأ جملة syntax error. إن تعليمة if-then-else في الواقع هي تعليمة واحدة، لذا لا يمكنك وضع فاصلة منقوطة في وسطها.

تعليمة if يمكن لها أن تكون أكثر تعقيدا. فالشرط يمكن تحويله إلى سلسلة من الشروط (باستخدام and و or و not)، أو ان تعليمة if تتفرع عنها تعليمة if أخرى. الزرّين الأخيرين في مثال IfTest يعرضان هاتين الحالتين:

procedure TForm1.Button3Click(Sender: TObject);
begin
  // statement with a double condition
  if CheckBox1.Checked and CheckBox2.Checked then
    ShowMessage ('Both check boxes are checked')
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  // compound if statement
  if CheckBox1.Checked then
    if CheckBox2.Checked then
      ShowMessage ('CheckBox1 and 2 are checked')
    else
      ShowMessage ('Only CheckBox1 is checked')
  else
    ShowMessage (
      'Checkbox1 is not checked, who cares for Checkbox2?')
end;

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

تعليمات Case

إذا ما أضحت تعليمات if لديك أكثر تعقيدا، يمكنك استبدالها في أية لحظة بتعليمات case. تعليمة case عبارة عن تعبير يستخدم لاختيار قيمة، قائمة بقيم محتملة، أو مدى من القيم. هذه القيم هي ثوابت constants، و يجب أن تكون فريدة ومن نوع تراتبي ordinal. أحيانا، قد يوجد بها تعليمة else و التي يتم تنفيذها إذا لم تتوافق أي من الاحتمالات مع القيمة المعطاة. فيما يلي مثالين بسيطين:

case Number of
  1: Text := 'One';
  2: Text := 'Two';
  3: Text := 'Three';
end;

case MyChar of
  '+' : Text := 'Plus sign';
  '-' : Text := 'Minus sign';
  '*', '/': Text := 'Multiplication or division';
  '0'..'9': Text := 'Number';
  'a'..'z': Text := 'Lowercase character';
  'A'..'Z': Text := 'Uppercase character';
else
  Text := 'Unknown character';
end;

الحلقات في باسكال

للغة باسكال التعليمات التكرارية النمطية التي لمعظم لغات البرمجة، يتضمن هذا تعليمات for، و while، و repeat . معظم ما تفعله هذه الحلقات loops سيكون مألوفا اذا ما سبق وان استخدمت لغات برمجية أخرى، لذا سأغطّي هذه التعليمات بصورة مختصرة.

حلقة For

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

var
  K: Integer;
begin
  K := 0;
  for I := 1 to 10 do
    K := K + I;

نفس المثال كان يمكن كتابته باستخدام عدّاد معكوس:

begin
  K := 0;
  for I := 10 downto 1 do
    K := K + I;

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

ملاحظة: عدّاد حلقة for ليس بالضرورة أن يكون رقما. يمكن له أن يكون قيمة من نوع تراتبي، مثل حرف أو نوع سردي.

تعليمات While و Repeat

الفرق بين حلقة while-do و حلقة repeat-until هو أن التوليف code داخل تعليمة repeat ينفّذ دائما، مرّة واحدة على الأقل. تستطيع بسهولة فهم السبب بالإطّلاع على المثال البسيط:

while (I < 100) and (J < 100) do
begin
  // use I and J to compute something...
  I := I + 1;
  J := J + 1;
end;

repeat
  // use I and J to compute something...
  I := I + 1;
  J := J + 1;
until (I > 100) or (J > 100);

إذا كانت القيمة الإبتدائية في I أو J أكبر من 100، فإن التعليمات داخل حلقة repeat-until سيتم تنفيذها مرة على كل حال.

الفرق الرئيسي الآخر بين هذين الحلقتين هو أن حلقة repeat-until لديها شرط محجوز reserved . الحلقة سيتم تنفيذها حتى اللحظة التي لا يتم فيها تحقيق الشرط. عندما يتحقق الشرط، تتوقف الحلقة. هذا عكس حلقة while-do ، التي تنفذ ما دام الشرط موجبا. لهذا السبب عليّ أن أعكس الشرط في التوليف أعلاه للحصول على تعليمة مشابهة.

مثال عن الحلقات

لإستكشاف تفاصيل الحلقات، دعنا نستعرض مثال دلفي بسيط. برنامج Loops يبرز الفرق بين حلقة بعدّاد ثابت و حلقة بعدّاد عشوائي تقريبا. إبدأ بمشروع project جديد، ضع مربّع قائمة list box و زرّيّن على النموذج form الرئيسي، قم بإعطاء الزرّين إسمين مناسبين (BtnFor و BtnWhile) و ذلك بتوصيف سِمة Name فيهما بواسطة معاين الكائنات Object Inspector. يمكن أيضا إزالة كلمة Btn من سِمة Caption (و دائما اضف الحرف & للعنوان لتنشيط الحرف التالي له كمفتاح اختصار shortcut). فيما يلي ملخّص للوصف النصّي للنموذج:

object Form1: TForm1
  Caption = 'Loops'
  object ListBox1: TListBox ...
  object BtnFor: TButton
    Caption = '&For'
    OnClick = BtnForClick
  end
  object BtnWhile: TButton
    Caption = '&While'
    OnClick = BtnWhileClick
  end
end

الشكل 5.2: في كل مرة تضغط فيها زرّ For في مثال Loops، يُملأ مربّع القائمة بأرقام متتالية.

الآن يمكنا اضافة بعض التوليف لحدثي OnClick في الزّرين. الزّر الأول به حلقة for بسيطة لعرض قائمة من الأرقام، كما هو في الشكل 5.2. قبل تنفيذ هذه الحلقة، التي تضيف عددا من الجمل إلى سِمة Items في مرّبع القائمة، تحتاج لتصفية محتويات القائمة نفسها.

procedure TForm1.BtnForClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Items.Clear;
  for I := 1 to 20 do
    Listbox1.Items.Add ('String ' + IntToStr (I));
end;

التوليف المربوط بالزّر الثاني أكثر تعقيدا نوعا ما. ففي هذه الحالة، توجد حلقة while قائمة على عدّاد، يتم زيادته عشوائيا. لإنجاز ذلك، قمت باستدعاء الإجرائية Randomize، والتي تقوم بإعادة تهيئة مولّد الرقم العشوائي، و وظيفة Random بنطاق مداه 100. نتيجة هذه الوظيفة هو رقم بين 0 و 99، يتم إختيارها عشوائيا. سلسلة الأرقام العشوائية تتحكم في عدد مرّات تنفيذ حلقة while.

procedure TForm1.BtnWhileClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Items.Clear;
  Randomize;
  I := 0;
  while I < 1000 do
  begin
    I := I + Random (100);
    Listbox1.Items.Add ('Random Number: ' + IntToStr (I));
  end;
end;

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

الشكل 5.3: محتويات القائمة في مثال Loops تتغير كل مرة تضغط فيها على زرّ while. لأن عدّاد الحلقة يزداد بقيمة عشوائية، في كل مرة تضغط فيها على الزر، يتمّ تنفيذ الحلقة بعدد مرات مختلف.

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

تعليمة With

أخر نوع من تعليمات باسكال سأقوم بالتركيز عليه هي تعليمة with ، و التي تعدّ مميزة في هذه اللغة البرمجية (و تم إدخالها مؤخّرا في فيجوال بيسك) و مفيدة جدا في البرمجة بدلفي.

تعليمة with ليس إلا اختصار shorthand. عندما تحتاج إلى الاشارة الى متغير نوع تسجيلة record (أو كائن object)، فبدلا من تكرار اسمه في كل مرّة، يمكنك استخدام تعليمة with . مثال ذلك، بينما أقوم بعرض نوع تسجيلة كتبت التوليف التالي:

type
  Date = record
    Year: Integer;
    Month: Byte;
    Day: Byte;
  end;

var
  BirthDay: Date;

begin
  BirthDay.Year := 1997;
  BirthDay.Month := 2;
  BirthDay.Day := 14;

باستعمال تعليمة with، بامكاني تحسين الجزء الأخير من التوليف، كالتالي:

begin
  with BirthDay do
  begin
    Year := 1995;
    Month := 2;
    Day := 14;
  end;

هذا الاسلوب يمكن استخدامه في برامج دلفي للإشارة الى المكوّنات components و أنواع الطبقات class الأخرى. مثلا، يمكننا إعادة كتابة الجزء الأخير من آخر مثال، مثال Loops، باستخدام تعليمة with لمناولة العناصر items في القائمة:

procedure TForm1.WhileButtonClick(Sender: TObject);
var
  I: Integer;
begin
  with ListBox1.Items do
  begin
    Clear; // shortcut
    Randomize;
    I := 0;
    while I < 1000 do
    begin
      I := I + Random (100);
      // shortcut:
      Add ('Random Number: ' + IntToStr (I));
    end;
  end;
end;

عندما تتعامل مع المكوّنات components أو الطبقات classes في باسكال عموما، تسمح لك تعليمة with بالاستغناءعن كتابة بعض التوليف، خاصة بالنسبة للحقول المتفرعة. مثلا، لنفترض انك تريد تغيير حجم و لون قلم الرسم لنموذج form. يمكنك كتابة التوليف التالي:

Form1.Canvas.Pen.Width := 2;
Form1.Canvas.Pen.Color := clRed;

و لكنه بالتأكيد سيكون الأمر أسهل لو كتبت التوليف التالي:

with Form1.Canvas.Pen do
begin
  Width := 2;
  Color := clRed;
end;

عندما تقوم بكتابة توليفا متشعبا، يمكن لتعليمة with أن تكون فعالة و تعفيك من تعريف بعض المتغيرات المؤقتة، و لكنها لا تخلو من العيوب. فبامكانها أن تجعل من التوليف أقل مقروئية، خاصة عندما تتعامل مع كائنات مختلفة لكن لديها سمات متشابه أو متطابقة.

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

with Button1 do
begin
  Width := 200;
  Caption := 'New Caption';
  Color := clRed;
end;

هذا التوليف يغير من عنوان Caption و عرض With الزرّ، و لكنه يؤثّر في سِمة اللون Color للشكل، و ليس في الزرّ! سبب هذا أن المكوّن TButton ليس لديه سِمة Color، و حيث أن التوليف يتم تنفيذه داخل كائن form نموذج الذي لديه مثل هذه السِمة فإن الافتراض الأول يتجه له مباشرة. بدلا من ذلك إذا كتبنا:

Button1.Width := 200;
Button1.Caption := 'New Caption';
Button1.Color := clRed; // error!

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

يجب أن تتجنب الاستخدام المتعدد لتعليمات with ، مثل:

with ListBox1, Button1 do...

فالتوليف الذي سيتبعه سيكون غالبا غير مقروء و صعب التتبع، لأنه مع كل سِمة يتم تحديدها في هذا الحيّز تحتاج إلى استنتاج و معرفة المكوّن المقصود الذي تتبعه هذه السِمة، بالاعتماد على السِمات ذات العلاقة و ترتيب المكونات في تعليمة with.

ملاحظة: بصدد الكلام عن المقروئية، لا تملك باسكال تعليمات مثل endif أو endcase. إذا كان لتعليمة if حيز begin-end، فإن نهاية هذا الحيز يحدد نهاية التعليمة. بالمقابل، تعليمة case تنتهي دائما بكلمة end. كل تعليمات end هذه، التي غالبا ما تكون واحدة فوق الأخرى، يمكن أن تجعل من التوليف صعب التتبع. فقط من خلال تتبع الهوامش يمكن معرفة تبعية كل end و لأية تعليمة. الطريقة العامة المتّبعة لحل هذه المشكلة و لجعل التوليف مفهوما أكثر هو في اضافة ملاحظة بعد تعليمة end تشير إلى تبعيتها، كما في:

if ... then
 ...
end; // if

ملخّص

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

الفصل التالي: الإجراءات و الوظائف

حقوق النسخ محفوظة لماركو كانتو؛ وينتش ايطاليا © Copyright Marco Cantù, Wintech Italia Srl 1995-2000
حقوق الترجمة: خالد الشقروني ، 2000