Skip to content

5. الوظائف والإجراءات

5.1. الدوال المحددة مسبقًا في VBScript

تستمد لغة البرمجة ثراءها إلى حد كبير من مكتبة وظائفها، حيث يمكن تغليف هذه الوظائف في كائنات تحت اسم «طرق». ومن هذا المنظور، يمكن اعتبار لغة VBScript فقيرة نسبيًا.

يحدد الجدول التالي وظائف VBScript خارج الكائنات. ولن ندخل في تفاصيلها هنا. فأسماءها تشير عمومًا إلى دورها. ويمكن للقارئ الرجوع إلى الوثائق للحصول على تفاصيل حول وظيفة معينة.

Abs
Array
Asc
Atn
CBool
CByte
CCur
CDate
CDbl
Chr
CInt
CLng
التحويلات
Cos
CreateObject
CSng
التاريخ
DateAdd
DateDiff
DatePart
DateSerial
DateValue
اليوم
الرياضيات المشتقة
التقييم
Exp
Filter
FormatCurrency
FormatDateTime
FormatNumber
FormatPercent
GetLocale
GetObject
GetRef
سداسي عشري
الساعة
InputBox
InStr
InStrRev
دولي، ثابت
IsArray
IsDate
IsEmpty
IsNull
IsNumeric
IsObject
انضم
LBound
LCase
يسار
Len
LoadPicture
السجل
LTrim؛ RTrim؛ والتشطيبات
الرياضيات
متوسط
الدقيقة
Month
MonthName
MsgBox
الآن
أكتوبر
استبدال
RGB
يمين
Rnd
Round
ScriptEngine
ScriptEngineBuildVersion
ScriptEngineMajorVersion
ScriptEngineMinorVersion
الثاني
SetLocale
التوقيع
Sin
مسافة
تقسيم
Sqr
StrComp
سلسلة
تان
الوقت
المؤقت
TimeSerial
TimeValue
TypeName
UBound
UCase
VarType
يوم الأسبوع
WeekdayName
السنة

5.2. البرمجة المعيارية

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

  • قراءة بيانات من لوحة المفاتيح أو القرص
  • كتابة بيانات على الشاشة أو على الطابعة أو على القرص، إلخ
  • حساب التعبيرات
  • التنقل داخل ملف
  • ...

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

يمكن في البداية وصف الحل بالشكل التالي:

  début
        lire les valeurs et les mettre dans un tableau T
        trier le tableau T
        écrire les valeurs triées du tableau T à l'écran
  fin

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

   début
         lire_tableau(T)
         trier_tableau(T)
         écrire_tableau(T)
   fin

حيث يمثل T مصفوفة. العمليات

    . lire_tableau(T)
    . trier_tableau(T)
    . écrire_tableau(T)

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

الوحدة النمطية lire_tableau(T)
الوحدة النمطية trier_tableau(T)
الوحدة النمطية écrire_tableau(T)

يمكن وصف الوحدة النمطية lire_tableau(T) على النحو التالي:


début
    écrire "Tapez la suite de valeurs à trier sous la forme val1 val2 ... : "
    lire valeurs
    construire tableau T à partir de la chaîne valeurs
fin

لقد قمنا هنا بوصف الوحدة النمطية lire_tableau بشكل كافٍ. ففي الواقع، تتوفر ترجمة فورية في لغة VBScript للإجراءات الثلاثة المطلوبة. أما الإجراء الأخير فسيتطلب استخدام دالة split. ولو لم تكن لغة VBScript تحتوي على هذه الدالة، لكان لا بد من تقسيم الإجراء 3 بدوره إلى إجراءات أولية لها ما يعادلها مباشرة في لغة VBScript.

يمكن وصف الوحدة النمطية écrire_tableau(T) على النحو التالي:


début
    construire chaîne texte "valeur1,valeur2,...." à partir du tableau T
    écrire texte
fin

يمكن وصف الوحدة النمطية écrire_tableau(T) على النحو التالي (بافتراض أن مؤشرات عناصر T تبدأ من 0):

début
      N<-- indice dernier élément du tableau T
      pour IFIN variant de N à 1
      faire
           //البحث عن مؤشر IMAX لأكبر عنصر في T
           // IFIN هو مؤشر العنصر الأخير في T

          chercher_max(T, IFIN, IMAX) 

           // نستبدل العنصر الأكبر في T بالعنصر الأخير في T

          échanger (T, IMAX, IFIN)

      finfaire
FIN

هنا تستخدم الخوارزمية مرة أخرى إجراءات غير أولية:


 . chercher_max(T, IFIN, IMAX)
 . échanger(T, IMAX, IFIN)

chercher_max(T, IFIN, IMAX) يُرجع المؤشر IMAX للعنصر الأكبر في المصفوفة T الذي يكون مؤشر آخر عنصر فيه هو IFIN.

تبديل(T، IMAX، IFIN) يقوم بتبديل عنصرين من المصفوفة T، وهما العنصران ذوا المؤشرين IMAX و IFIN.

لذلك، يجب وصف العمليات الجديدة غير الأولية.

الوحدة النمطية chercher_max(A, IFIN, IMAX)
   début
        IMAX<--0

        pour i variant de 1 à IFIN
        faire
           si T[i]>T[IMAX] alors
             début
                IMAX<--i
             fin
        finfaire
    fin
وحدة التبادل (T IMAX، IFIN)
  début
       temp<----T[IMAX]
       T[IMAX]<---T[IFIN]
       T[IFIN]<---temp
  fin

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

المبدأ المطبق هنا هو ما يُعرف بـ «التحليل التنازلي». إذا قمنا بتمثيل الهيكل الأساسي للحل، فسنحصل على ما يلي:

لدينا بنية شجرية.

5.3. دوال وإجراءات VBScript

بمجرد إتمام التحليل المعياري، يمكن للمبرمج ترجمة وحدات خوارزميته إلى VBScript مثل fonctions أو procédures. تقبل كل من fonctions و procédures معلمات الإدخال/الإخراج، لكن fonction تُرجع نتيجة تسمح باستخدامها في التعبيرات، في حين أن procédure لا تُرجع أي نتيجة.

5.3.1. إعلان الدوال والإجراءات في VBScript

يتم تعريف إجراء VBScript على النحو التالي

sub nomProcédure([Byref/Byval] param1, [Byref/Byval] param2, ...)
    instructions
end sub

أما إعلان الدالة فهو كما يلي

function nomFonction([Byref/Byval] param1, [Byref/Byval] param2, ...)
    instructions
end sub

لإرجاع النتيجة، يجب أن تتضمن الدالة تعليماً لتعيين النتيجة إلى متغير يحمل اسم الدالة:

اسم_الدالة = النتيجة

يتوقف تنفيذ الدالة أو الإجراء بطريقتين:

  1. عند الوصول إلى تعليمة نهاية الدالة (end function) أو نهاية الإجراء (end sub)
  2. عند الوصول إلى تعليمة الخروج من الدالة (exit function) أو الإجراء (exit sub)

بالنسبة للدالة، تجدر الإشارة إلى أنه يجب تعيين النتيجة لمتغير يحمل اسم الدالة قبل أن تنتهي الدالة بعبارة end function أو exit function.

5.3.2. طرق تمرير معلمات الدالة أو الإجراء

عند إعلان معلمات الإدخال والإخراج لدالة أو إجراء، يتم تحديد طريقة (byRef، byVal) نقل المعلمة من البرنامج المستدعي إلى البرنامج المستدعى:

sub nomProcédure([Byref/Byval] param1, [Byref/Byval] param2, ...)

function nomFonction([Byref/Byval] param1, [Byref/Byval] param2, ...)

عندما لا يتم تحديد وضع الإرسال byRef أو byVal، يتم استخدام الوضع byRef.

المعلمات الفعلية، المعلمات الشكلية

لنفترض أن هناك دالة VBScript مُعرَّفة على النحو التالي

function nomFonction([Byref/Byval] paramForm1, [Byref/Byval] paramForm2, ...)
...
end function

تُسمى المعلمات parmamFormi المستخدمة في تعريف الدالة أو الإجراء بالمعلمات الشكلية. يمكن استخدام الدالة السابقة من البرنامج الرئيسي أو من وحدة نمطية أخرى بواسطة تعليمة من النوع التالي:

résultat=nomFonction(paramEff1, paramEff2, ...)

تُسمى المعلمات parmamEffi المستخدمة في استدعاء الدالة أو الإجراء «المعلمات الفعلية». وعندما يبدأ تنفيذ الدالة nomFonction، تتلقى المعلمات الشكلية قيم المعلمات الفعلية المقابلة. تحدد الكلمات الرئيسية byRef و byVal طريقة نقل هذه القيم.

طريقة النقل بالقيمة (byVal)

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

طريقة النقل بالمرجع (byRef)

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

  • لمُتغيرات الإخراج لأن قيمها يجب أن تُنقل إلى البرنامج المستدعي
  • لمُتغيرات الإدخال التي يستغرق نسخها وقتًا طويلاً، مثل المصفوفات

يُظهر البرنامج التالي أمثلة على تمرير المعلمات:

البرنامج


Sub proc1(byval i, ByRef j, k)
  ' يتم تمرير i بالقيمة (byval) — وبالتالي يختلف المعامل الفعلي عن المعامل الشكلي
  ' يتم تمرير j بالقيمة (byref) — وبالتالي يكون المتغير الفعلي والمتغير الاسمي متطابقين
  ' لم يتم تحديد طريقة تمرير k. بشكل افتراضي، يتم التمرير بالمرجع
  i=i+1
  j=j+1
  k=k+1
  affiche "dans proc1",i,j,k
End Sub

 Sub affiche(byval msg, ByVal i, ByVal j, ByVal k)
  ' يعرض قيم i و j و k
  wscript.echo msg & " i=" & i & " j=" & j & " k=" & k
End Sub


' ------------- استدعاءات الدوال والإجراءات

' تعيين قيم i و j
  i=4:j=5 : k=6

' التحقق
  affiche "dans programme principal, avant l'appel à proc1 :",i,j,k

' استدعاء الإجراء proc1
  proc1 i,j,k

' التحقق
  affiche "dans programme principal, après l'appel à proc1 :",i,j,k

' نهاية
  wscript.quit 0

النتائج

dans programme principal, avant l'appel à proc1 : i=4 j=5 k=6
dans proc1 i=5 j=6 k=7
dans programme principal, après l'appel à proc1 : i=4 j=6 k=7

تعليقات

  • في البرنامج النصي vbscript، لا يوجد مكان محدد للدوال والإجراءات. يمكن وضعها في أي مكان في النص المصدري. بشكل عام، يتم تجميعها إما في البداية أو في النهاية، مع الحرص على أن يشكل البرنامج الرئيسي كتلة متصلة.

5.3.3. صيغة استدعاء الدوال والإجراءات

لنفترض أن هناك إجراءً p يقبل المعلمات الشكلية pf1، pf2، ...

  • يتم استدعاء الإجراء p بالصيغة التالية
p pe1, pe2, ...

دون أقواس حول المعلمات

  • وإذا كانت الإجراء p لا تقبل أي معلمات، فيمكن استخدام الاستدعاء p أو p() والإعلان sub p أو sub p() دون فرق

لنفترض أن هناك دالة f تقبل معلمات شكلية pf1، pf2، ...

  • يتم استدعاء الدالة f بالصيغة
résultat=f(pe1, pe2, ...)

يجب وضع الأقواس حول المعلمات. إذا كانت الدالة f لا تقبل أي معلمات، فيمكن استخدام الاستدعاء f أو f() والإعلان function f أو function f() دون فرق.

  • يمكن للبرنامج المستدعي تجاهل ناتج الدالة f. وعندئذ تُعتبر الدالة f إجراءً وتخضع لقواعد استدعاء الإجراءات. في هذه الحالة، نكتب f pe1, pe2, ... (بدون أقواس) لاستدعاء الدالة f.

إذا كانت الدالة أو الإجراء عبارة عن طريقة كائن، فيبدو أن القواعد تختلف بعض الشيء وتفتقر إلى التناسق.

  • فمن الممكن كتابة MyFile.WriteLine "هذا اختبار." أو MyFile.WriteLine("هذا اختبار.")
  • ولكن بينما يمكن كتابة wscript.echo 4، لا يمكن كتابة wscript.echo(4).

سنلتزم بالقواعد التالية:

  • لا توضع أقواس حول معلمات الإجراء أو الدالة المستخدمة كإجراء
  • وضع أقواس حول معلمات الدالة

5.3.4. بعض الأمثلة على الدوال

فيما يلي بعض الأمثلة على تعريفات الدوال واستخداماتها:

البرنامج


 Function plusgrandque(byval i, ByVal j)
  ' تُرجع القيمة المنطقية «صحيح» إذا كان i>j، وإلا تُرجع «خطأ»

  ' التحقق من البيانات
  If isnumeric(i) And isnumeric(j) Then
    If i>j Then
      plusgrandque=true
    Else
      plusgrandque=false
    End If
  Else
    wscript.echo "Arguments (" & i & "," & j & ") erronés"
    plusgrandque=false
  End If
  Exit Function
End Function

 Function rendUnTableau(byval n)
  ' تُرجع مصفوفة مكونة من n عنصر
  tableau=array()
  ' التحقق من صحة المعلمة n
  If isnumeric(n) And n>=1 Then
    ReDim Preserve tableau(n)
    For i= 0 To n-1
      tableau(i)=i
    Next
  Else
    wscript.echo "Argument [" & n & "] erroné"
  End If
  ' يتم إرجاع النتيجة
  rendUnTableau=tableau
End Function

 Function argumentsVariables(byref arguments)
  ' المعلمات عبارة عن مصفوفة من الأرقام يتم إرجاع مجموعها
  somme=0
  For i=0 To ubound(arguments)
    somme=somme+arguments(i)
  Next
  argumentsVariables=somme
End Function

  ' دالتان بدون معلمات مُعلَنتان بطريقتين مختلفتين
  Function sansParametres1
    sansParametres=4
  End Function

  Function sansParametres2()
    sansParametres=4
  End Function


' ------------- استدعاءات الدوال والإجراءات

' استدعاءات الدالة plusgrandque
  wscript.echo "plusgrandque(10,6)=" & plusgrandque(10,6)
  wscript.echo "plusgrandque(6,10)=" & plusgrandque(6,10)
  wscript.echo "plusgrandque(6,6)=" & plusgrandque(6,6)
  wscript.echo "plusgrandque(6,'a')=" & plusgrandque(6,"a")

' استدعاءات الدالة rendUnTableau
  monTableau=rendUnTableau(10)
  For i=0 To ubound(monTableau)
    wscript.echo monTableau(i)
  Next
  monTableau=rendUnTableau(-6)
  For i=0 To ubound(monTableau)
    wscript.echo monTableau(i)
  Next

' استدعاءات الدالة argumentsVariables
  wscript.echo "somme=" & argumentsVariables(array(-1,2,7,8))
  wscript.echo "somme=" & argumentsVariables(array(-1,10,12))

' استدعاءات الدوال بدون معلمات
  res=sansParametres1
  res=sansParametres1()
  sansParametres1
  sansParametres1()

  res=sansParametres2
  res=sansParametres2()
  sansParametres2
  sansParametres2()

' النهاية
  wscript.quit 0

النتائج

plusgrandque(10,6)=Vrai
plusgrandque(6,10)=Faux
plusgrandque(6,6)=Faux
Arguments (6,a) erronés
plusgrandque(6,'a')=Faux
0
1
2
3
4
5
6
7
8
9

Argument [-6] erroné
somme=16
somme=21
somme=10

تعليقات

  • تُظهر الدالة rendUnTableau أن الدالة يمكن أن تُرجع عدة نتائج وليس نتيجة واحدة فقط. يكفي أن تضعها في متغير من نوع المصفوفة وأن تُرجع هذا المتغير كنتيجة.
  • وعلى العكس من ذلك، توضح الدالة argumentsVariables أنه يمكن كتابة دالة تقبل عددًا متغيرًا من الوسيطات. ويكفي هنا أيضًا وضعها في متغير صفيف وجعل هذا المتغير معلمة للدالة.

5.3.5. معلمة الإخراج أو نتيجة الدالة

لنفترض أن تحليل أحد التطبيقات أظهر الحاجة إلى وحدة نمطية M ذات معلمات إدخال Ei ومعلمات إخراج Sj. تجدر الإشارة إلى أن معلمات الإدخال هي معلومات يقدمها البرنامج المستدعي إلى البرنامج المستدعى، وبالعكس، فإن معلمات الإخراج هي معلومات يقدمها البرنامج المستدعى إلى البرنامج المستدعي. توجد في VBScript عدة حلول لمعلمات الإخراج:

  • إذا كان هناك معلمة إخراج واحدة فقط، فيمكن جعلها نتيجة دالة. وبذلك لا تكون هناك معلمة إخراج بعد الآن، بل مجرد نتيجة دالة.
  • إذا كان هناك n معلمات إخراج، فيمكن استخدام إحداها كنتيجة دالة، بينما تظل المعلمات الـ n-1 الأخرى معلمات إخراج. كما يمكن عدم استخدام دالة، بل استخدام إجراء (procedure) له n معلمات إخراج. ويمكن أيضًا استخدام دالة تُرجع مصفوفة نضع فيها القيم الـ n المطلوب إرجاعها إلى البرنامج المستدعي. تجدر الإشارة إلى أن البرنامج المستدعى يُرجع نتائجه إلى البرنامج المستدعي عن طريق نسخ القيم. ويتم تجنب هذا النسخ في حالة معلمات الإخراج التي تُمرر بالرجوع. لذا فإن هذا الحل الأخير يوفر وقتًا.

5.4. برنامج Vbscript لفرز القيم

كنا قد بدأنا مناقشة البرمجة المعيارية بدراسة خوارزمية لفرز القيم الرقمية التي يتم إدخالها عبر لوحة المفاتيح. وفيما يلي الترجمة VBScript التي يمكن إجراؤها لذلك:

البرنامج

' البرنامج الرئيسي
Option Explicit

Dim T        ' le tableau de valeurs à trier

' قراءة القيم
T=lire_tableau

' فرز القيم
trier_tableau T

' عرض القيم المصنفة
ecrire_tableau T

' النهاية
wscript.quit 0

' ---------- الوظائف والإجراءات

' -------- lire_tableau
Function lire_tableau
     ' يُطلب إدخال القيم
    wscript.stdout.write "Tapez les valeurs à trier sous la forme val1 val2  ... valn : "
     ' يتم قراءتها
    Dim valeurs
    valeurs=wscript.stdin.readLine
     ' يتم وضعها في مصفوفة
    lire_tableau=split(valeurs," ")
End Function

' -------- ecrire_tableau
Sub ecrire_tableau(byref T)
     ' يعرض محتوى الجدول T
    wscript.echo join(T," ")
End Sub

' -------- trier_tableau
Sub trier_tableau (byref T)
     ' يُرتب الجدول T بترتيب تصاعدي

     ' نبحث عن المؤشر imax للمصفوفة T[0..ifin]
     ' لتبديل T[imax] مع العنصر الأخير من المصفوفة T[0..ifin]
     ' ثم نكرر العملية مع مصفوفة تحتوي على عنصر واحد أقل

    Dim ifin, imax, temp
    For ifin=ubound(T) To 1 Step -1
         ' نبحث عن المؤشر imax للمصفوفة T[0..ifin]
        imax=chercher_max(T,ifin)
         ' نستبدل العنصر «max» بالعنصر الأخير من المصفوفة T[0..ifin]
        temp=T(ifin):T(ifin)=T(imax):T(imax)=temp
    Next
End Sub

' -------- chercher_max
Function chercher_max(byRef T, ByVal ifin)
     ' نبحث عن المؤشر imax للمصفوفة T[0..ifin]
    Dim i, imax
    imax=0
    For i=1 To ifin
        If cdbl(T(i))>cdbl(T(imax)) Then imax=i
    Next

     ' نُرجع النتيجة
    chercher_max=imax
End Function

النتائج

Tapez les valeurs à trier sous la forme val1 val2  ... valn : 10 9 8 7 6 1
1 6 7 8 9 10

تعليقات:

  • لم يتم إنشاء وحدة برمجية بلغة VBScript للوحدة النمطية échanger التي تم تحديدها في الخوارزمية الأولية، وذلك لأنها اعتُبرت بسيطة جدًا بحيث لا تستدعي إنشاء وحدة برمجية خاصة بها.

5.5. البرنامج IMPOTS في شكل وحدات

نستأنف برنامج حساب الضريبة، وقد تمت كتابته هذه المرة في شكل وحدات

البرنامج

' حساب ضريبة أحد دافعي الضرائب
' يجب استدعاء البرنامج بثلاثة معلمات: متزوج، أطفال، راتب
' متزوج: الحرف O إذا كان متزوجًا، وN إذا كان غير متزوج
' الأطفال: عدد الأطفال
' الراتب: الراتب السنوي بدون السنتات

' الإعلان الإلزامي عن المتغيرات
Option Explicit
Dim erreur

' يتم استرداد الوسيطات بالتحقق من صحتها
Dim marie, enfants, salaire
erreur=getArguments(marie,enfants,salaire)
' خطأ؟
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit erreur(0)

' يتم استرداد البيانات اللازمة لحساب الضريبة
Dim limites, coeffR, coeffN
getData limites,coeffR,coeffN

' عرض النتيجة
wscript.echo "impôt=" & calculerImpot(marie,enfants,salaire,limites,coeffR,coeffN)

' يتم الخروج دون أخطاء
wscript.quit 0

' ------------ الوظائف والإجراءات

' ----------- getArguments
Function getArguments(byref marie, ByRef enfants, ByRef salaire)
     ' يجب استرداد ثلاث قيم تم تمريرها كمعاملات إلى البرنامج الرئيسي
     ' يتم تمرير الحجة إلى البرنامج دون مسافات أمامها أو خلفها
     ' سيتم استخدام التعبيرات النمطية للتحقق من صحة البيانات

     ' تُرجع متغيرًا من نوع مصفوفة الأخطاء يحتوي على قيمتين
     ' خطأ(0): رمز الخطأ، 0 في حالة عدم وجود خطأ
     ' خطأ(1): رسالة خطأ في حالة وجود خطأ، وإلا فإن السلسلة فارغة

    Dim syntaxe
    syntaxe= _
    "Syntaxe : pg marié enfants salaire" & vbCRLF & _
    "marié : caractère O si marié, N si non marié" & vbCRLF & _
    "enfants : nombre d'enfants (entier >=0)" & vbCRLF & _
    "salaire : salaire annuel sans les centimes (entier >=0)"

     ' نتحقق من وجود 3 معلمات
    Dim nbArguments
    nbArguments=wscript.arguments.count
    If nbArguments<>3 Then
         ' رسالة خطأ
        getArguments= array(1,syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect")
         ' النهاية
        Exit Function
    End If

    Dim modele, correspondances
    Set modele=new regexp

     ' يجب أن يكون الحالة الاجتماعية من بين الأحرف oOnN
    modele.pattern="^[oOnN]$"
    Set correspondances=modele.execute(wscript.arguments(0))
    If correspondances.count=0 Then
         ' رسالة خطأ
        getArguments=array(2,syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect")
         ' الخروج
        Exit Function
    End If
     ' استرداد القيمة
    If lcase(wscript.arguments(0)) = "o"Then
        marie=true
    Else
        marie=false
    End If

     ' يجب أن تكون «الأطفال» عددًا صحيحًا >=0
    modele.pattern="^\d{1,2}$"
    Set correspondances=modele.execute(wscript.arguments(1))
    If correspondances.count=0 Then
         ' خطأ
        getArguments= array(3,syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect")
         ' الخروج
        Exit Function
    End If
     ' يتم استرداد القيمة
    enfants=cint(wscript.arguments(1))

     ' يجب أن يكون الراتب عددًا صحيحًا >=0
    modele.pattern="^\d{1,9}$"
    Set correspondances=modele.execute(wscript.arguments(2))
    If correspondances.count=0 Then
         ' خطأ
        getArguments= array(4,syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect")
         ' الخروج
        Exit Function
    End If
     ' يتم استرداد القيمة
    salaire=clng(wscript.arguments(2))

     ' انتهى دون أخطاء
    getArguments=array(0,"")
End Function

' ----------- getData
Sub getData(byref limites, ByRef coeffR, ByRef coeffN)
     ' نحدد البيانات اللازمة لحساب الضريبة في 3 جداول
    limites=array(12620,13190,15640,24740,31810,39970,48360, _
    55790,92970,127860,151250,172040,195000,0)
    coeffr=array(0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45, _
    0.5,0.55,0.6,0.65)
    coeffn=array(0,631,1290.5,2072.5,3309.5,4900,6898.5,9316.5, _
    12106,16754.5,23147.5,30710,39312,49062)
End Sub

' ----------- calculerImpot
Function calculerImpot(byval marie,ByVal enfants,ByVal salaire, ByRef limites, ByRef coeffR, ByRef coeffN)

     ' يتم حساب عدد الحصص
    Dim nbParts
    If marie=true Then
        nbParts=(enfants/2)+2
    Else
        nbParts=(enfants/2)+1
    End If
    If enfants>=3 Then nbParts=nbParts+0.5

     ' يتم حساب الحصة العائلية والدخل الخاضع للضريبة
    Dim revenu, qf
    revenu=0.72*salaire
    qf=revenu/nbParts

     ' يتم حساب الضريبة
    Dim i, impot
    i=0
    Do While i<ubound(limites) And qf>limites(i)
        i=i+1
    Loop
    calculerImpot=int(revenu*coeffr(i)-nbParts*coeffn(i))
End Function

تعليقات

  • تسمح الدالة getArguments باسترداد المعلومات (الزوجة، الأبناء، الراتب) الخاصة بالمكلف. وهنا، يتم تمرير هذه المعلومات كمعلمات إلى برنامج VBScript. إذا تغير هذا الأمر، على سبيل المثال إذا كانت هذه المعلمات تأتي من واجهة رسومية، فسيكون من الضروري إعادة كتابة الإجراء getArguments فقط دون غيره.
  • يمكن للدالة getArguments اكتشاف الأخطاء في المعلمات. وعندما يحدث ذلك، كان من الممكن اتخاذ قرار بوقف تنفيذ البرنامج في الدالة getArguments باستخدام الأمر wscript.quit. ولا يجب أبدًا القيام بذلك داخل دالة أو إجراء. إذا اكتشفت دالة أو إجراءً ما وجود خطأ، فيجب عليها الإبلاغ عنه بطريقة أو بأخرى إلى البرنامج المستدعي. فالقرار بشأن إيقاف التنفيذ من عدمه يعود إلى البرنامج المستدعي، وليس إلى الإجراء. في مثالنا هذا، قد يقرر البرنامج المستدعي مطالبة المستخدم بإعادة إدخال البيانات الخاطئة عبر لوحة المفاتيح بدلاً من إيقاف التنفيذ.
  • هنا، تُرجع الدالة getArguments متغيرًا من نوع «مصفوفة» حيث يكون العنصر الأول رمز خطأ (0 في حالة عدم وجود خطأ) والعنصر الثاني رسالة خطأ في حالة وجود خطأ. ومن خلال فحص النتيجة التي تم الحصول عليها، يمكن للبرنامج المستدعي معرفة ما إذا كان هناك خطأ أم لا.
  • تسمح الإجراء getData بالحصول على البيانات اللازمة لحساب الضريبة. وهنا يتم تعريفها مباشرةً في الإجراء getData. وإذا كانت هذه البيانات ستأتي من مصدر آخر، مثل ملف أو قاعدة بيانات على سبيل المثال، فيجب إعادة كتابة الإجراء getData فقط دون غيره.
  • تتيح الدالة calculerImpot حساب الضريبة بمجرد الحصول على جميع البيانات، بغض النظر عن الطريقة التي تم الحصول عليها بها.
  • وتجدر الإشارة إلى أن البرمجة المعيارية تتيح (إعادة) استخدام بعض الوحدات النمطية في سياقات مختلفة. وقد تطور هذا المفهوم بشكل كبير خلال العشرين عامًا الماضية في إطار مفهوم الكائنات.