الماكرو هو مجموعة من الأوامر (مجموعة تعليمات) يمكن تكرارها بسهولة في أي مكان من البرنامج. أو بمعنى آخر هو مجموعة تعليمات يتم إعطاؤها اسماً بحيث كلما واجه المترجم هذا الاسم يستبدله بمجموعة التعليمات.
يتم تعريف الماكرو بالشكل التالي:
عرف اسم_الماكرو: ماكرو [معطيات] { // متن_الماكرو }
def macro_name: macro [parameters] { // macro_body }
أو بالصيغة المختصرة:
ماكرو اسم_الماكرو [معطيات] { // متن الماكرو }
macro macro_name [parameters] { // macro_body }
حيث أن:
اسم_الماكرو (macro_name): اسم يستخدم لاحقًا لاستدعاء الماكرو.
ماكرو (macro): كلمة مفتاحية.
معطيات (parameters): معطيات الماكرو التي سيتم استخدامها (تعويضها) في متن الماكرو.
متن_الماكرو (macro_body): متن الماكرو حيث سنضع التعليمات البرمجية (في حال كانت التعليمات عبارة عن تعليمة واحدة يمكنك الاستغناء عن القوسين الحاصرين).
المثال الأول:
هنا سنعرف ماكرو باسم `_أمد_` (LIMIT) وسيحمل القيمة 5. وبالتالي أينما واجه المترجم اسم هذا الماكرو سيدرك أننا نقصد القيمة 5.
اشمل "مـتم/طـرفية"؛ ماكرو _أمد_ 5؛ // تعريف ماكرو بدون وسطاء مـتم.طـرفية.اطبع("قيمة _أمد_ هي %d\ج"، _أمد_[])؛ // قيمة _أمد_ هي 5
import "Srl/Console.alusus"; macro LIMIT 5; // تعريف ماكرو بدون وسطاء Srl.Console.print("The value of LIMIT is %d\n", LIMIT[]); //The value of LIMIT is 5
المثال الثاني:
سنستخدم الآن الماكرو لحساب مساحة مستطيل.
اشمل "مـتم/طـرفية"؛ ماكرو _مساحة_ [س، ص] س * ص؛ عرف ا: صحيح = 4؛ عرف ب: صحيح = 9؛ عرف مساحة: صحيح؛ مساحة = _مساحة_[ا، ب]؛ مـتم.طـرفية.اطبع("مساحة المستطيل هي: %d\ج"، مساحة)؛ // مساحة المستطيل هي: 36
import "Srl/Console.alusus"; macro AREA [x,y] x*y; def a: int = 4; def b: int = 9; def area: int; area = AREA[a, b]; Srl.Console.print("Area of rectangle is: %d\n", area); // Area of rectangle is: 36
من البرنامج أعلاه يمكننا أن نرى أنه كلما وجد المترجم [x, y]AREA في البرنامج فإنه يستبدلها بمتن الماكرو بعد استعاضة المعطيات ما يقابلها، أي x * y.
المثال الثالث:
اشمل "مـتم/طـرفية"؛ اشمل "مـتم/نـص"؛ استخدم مـتم؛ عرف ن: نـص ="ماكرو.."; ماكرو اطبع_نصا [م] طـرفية.اطبع("%s"، م.صوان)؛ اطبع_نصا[ن]؛ // ماكرو..
import "Srl/Console.alusus"; import "Srl/String.alusus"; use Srl; def s: String = "Macro.."; macro printString [s] Console.print("%s", s.buf); printString[s]; // Macro...
لاحظ أنه عند استخدام المتغيرات في الماكرو لانقوم بتحديد صنفها (ولايمكننا ذلك)، وإنما يتم تحديده تلقائياً.
ملاحظات:
مثال:
اشمل "مـتم/طـرفية"؛ ماكرو _انستجرام_ _متابعون_[]؛ ماكرو _متابعون_ 100؛ مـتم.طـرفية.اطبع("لدى الأسس %d متابعا على انستجرام\ج"، _انستجرام_[])؛ // لدى الأسس 100 متابعا على انستجرام
import "Srl/Console.alusus"; macro INSTAGRAM FOLLOWERS[]; macro FOLLOWERS 100; Srl.Console.print("Alusus has %dK followers on Instagram\n", INSTAGRAM[]); // Alusus has 100K followers on Instagram
يمكنك الاطلاع على الفرق بين ماكرو لغة الأسُس وماكرو لغة السي من هنا
على الرغم من التشابه الكبير بين وحدات الماكرو و الدوال إلا أن هناك بعض الحالات والفوائد التي قد تجعلنا نستخدم الماكرو، منها:
اشمل "مـتم/طـرفية"؛ ماكرو عرف_س { عرف س: صحيح = 9؛ } عرف_س[]؛ مـتم.طـرفية.اطبع("%d"، س)؛ // 9
import "Srl/Console.alusus"; macro defX { def x: int = 9; } defX[] Srl.Console.print("%d", x); // 9لاحظ كيف أنه بمجرد استدعاء الماكرو أصبحنا قادرين على استخدام المتغير س.
اشمل "مـتم/طـرفية"؛ استخدم مـتم.طـرفية؛ ماكرو تربيع [س] { س * س } اطبع("%d\ج"، تربيع[5])؛ // 25 اطبع("%0.2f\ج"، تربيع[5.5]~مثل[عائم[64]])؛ // 30.25
import "Srl/Console.alusus" use Srl.Console; macro square [x] { x * x } print("%d\n", square[5]); // 25 print("%0.2f\n", square[5.5]~cast[Float[64]]); // 30.25هنا يمكننا استخدام الماكرو `ماكرو` (square) مع أي صنف يقبل المؤثر *.
اشمل "مـتم/طـرفية"؛ ماكرو تربيع [س] { س * س } دالة د () { عرف س: صحيح = 9؛ مـتم.طـرفية.اطبع("%d"، تربيع[س])؛ } د()؛ // 81
import "Srl/Console.alusus"; macro square[x] { x * x } function f () { def x: int = 9; Srl.Console.print("%d", square[x]); } f() // 81الآن لو أزلت المعطى من الماكرو وافترضت أن الدالة يجب أن تعرف المتغير فهذا لا يمكنك فعله بالدوال. أي:
اشمل "مـتم/طـرفية"؛ ماكرو تربيع { س * س } دالة د () { عرف س: صحيح = 9؛ مـتم.طـرفية.اطبع("%d"، تربيع[])؛ } د()؛ // 81
import "Srl/Console.alusus"; macro square { x * x } function f () { def x: int = 9; Srl.Console.print("%d", square[]); } f(); // 81