المقدمة
صُممت لغة الأسُس لتكون لغة شاملة يمكن استخدامها لبناء أي برنامج كان مهما كان
اختصاصه أو بيئة عمله أو طريقة تنفيذه، وهذه الشمولية تتطلب تصميم قواعد اللغة
بشكل تجريدي غير مرتبط ببيئة عمل أو مجال محدد، وجعلها لغة قابلة للتطوير من
قبل المستخدم أو المجتمع بدلاً من حصر عملية التطوير في فريق محدد، إضافة إلى
تمكين المبرمج من الوصول إلى المترجم نفسه والتحكم فيه. كذلك فإن عملية التطوير
يجب أن تكون ممكنة دون الحاجة لإعادة بناء المترجم. تصميم اللغة يعتمد على المفاهيم
التالية:
مفهوم لغة الأسُس لبرمجيات الحاسوب
لغة الأسُس تعرّف برنامج الحاسوب تعريفاً لا يرتبط بطبيعة عمل البرنامج أو بيئته
التنفيذية، وإنما تعرفه على أنه مجموعة من الجمل تتكون كل منها من حدّ أو مجموعة
من الحدود وكل حدّ عبارة عن قيمة ثابتة أو اسم متغير أو تركيب أو أمر أو جملة
أخرى أو مجموعة من الجمل. بُنيت على هذا التعريف وبصورته الشمولية قواعد أساسية
للغة الأسُس وجُعلت هذه القواعد ديناميكية وأضيفت للغة الأسُس إمكانية إنشاء قواعد
مشتقة منها وهو ما يجعل قواعد اللغة قابلة للتوسيع دون الإضرار بالشكل العام
لقواعدها ودون التسبب بغموض الإعراب.
نظام ترجمة مفتوح ومرن ولامركزي
بدل إنتاج مترجم مغلق يفهم أنماط البرمجة المرجوّة وكيفية إنشاء الشفرة التنفيذية،
استبدلت لغة الأسُس هذا التصميم بتصميم مختلف يجعل الترجمة تتم بنظام مفتوح متعدد
الأجزاء مع وجود جزء مركزي يعمل عملاً إدارياً ويوفّر الأسُس التي تُبنى عليها الأجزاء
الأخرى. يتيح هذا الأسلوب توسيع اللغة وتطوير عملية الترجمة عن طريق استبدال
أجزاء بأخرى أو إضافة أجزاء جديدة. هذا النظام صُمم بأسلوب مفتوح يتيح لأي مبرمج
الوصول إلى الوحدات والبيانات الداخلية لنظام الترجمة لتطوير وحدات ترجمة جديدة
وهو ما يجعل اللغة قابلة للتطوير من قبل مجتمع المبرمجين بدل أن تكون عملية
التطوير حصراً على مجموعة محددة. يتيح هذا التصميم أيضاً إمكانية تطوير اللغة
آنياً على عدة جبهات من قبل فرق مختلفة. الشكل التالي يوضح الفرق بين أسلوب
الترجمة التقليدي وأسلوب الترجمة في لغة الأسُس:
التصميم العام
نظام الترجمة
بدل الاعتماد على مترجم أحادي (monolithic) تعتمد الترجمة في لغة الأسُس على نظام
ترجمة مركّب ولا مركزي ينقسم إلى:
- القلب:
وهو الجزء المركزي في لغة الأسُس. يُعرّف القلب القواعدَ الأساسية ويعمل على
تحليل الشفرة المصدرية وتنسيق عمل مكتبات البناء.
- مكتبات البناء:
تعمل مكتبات البناء على تعريف القواعد المخصصة وتحويل بيانات التحليل إلى
شفرة تنفيذية. هذه المكتبات تُربط بالقلب ديناميكياً ويُمكن للقلب تحميل عدد
غير محدد من هذه المكتبات. تحميل هذه المكتبات يتم عبر أوامر في الشفرة
المصدرية المراد ترجمتها.
الشكل التالي يوضح سيل البيانات من الشفرة المصدرية حتى الشفرة التنفيذية:
مكتبات البناء ليست سوى مكتبات ديناميكية تحتوي على أصناف وتعريفات متعلقة بالقواعد
وعملية الترجمة ويتم تحميلها بنفس الطريقة التي يتم فيها تحميل مكتبات أخرى، أي
باستخدام الأمر import داخل الشفرة المصدرية نفسها التي يُراد ترجمتها، وبذلك يكون
كل مشروع قادراً على اختيار الصفات اللغوية التي يحتاجها.
يحتوي القلب على
مستودع ديناميكي للتعريفات القواعدية يمكن لأي مكتبة بناء أن تضيف أو تعدل في محتواه
لإضافة قواعدها الخاصة أو معالجات بنائها الخاصة. يحتوي القلب أيضاً على مستودع عام
ومركزي للتعريفات يستخدم من قبل مكتبات البناء لتخزين ما ينتج من عملية البناء حسب
حاجتها ما يجعل هذه التعريفات متوفرة بشكل عمومي لجميع المكتبات ومتوفرة أيضاً
للشفرة المصدرية نفسها أيضاً.
الشكل التالي يوضح العلاقة بين الأجزاء المختلفة
في عملية الترجمة:
يمكن أيضاً تعريف قواعد إضافية ومعالجات بناء داخل الشفرة المصدرية نفسها التي يتم
ترجمتها، أي يستطيع البرنامج أن يعرف قواعده الخاصة شرط أن تسبق هذه التعريفات
استخدامَها داخل الشفرة المصدرية.
قواعد لغة الأسُس
قواعد لغة الأسُس تتصف بما يلي:
-
قواعد مبنية على البيانات (data driven): أي أن بالإمكان التحكم بالتعريفات
القواعدية عن طريق متغيرات.
-
قواعد متحركة (ديناميكية): قواعد لغة الأسُس متحركة وليست ثابتة، بمعنى أن
قواعد اللغة قابلة للإضافة أو التعديل أثناء الترجمة.
-
الإشتقاق القواعدي: يمكن في لغة الأسُس اشتقاق قواعد من قواعد أخرى باستخدام
التوريث القواعدي الذي يسمح للقاعدة الوارثة أن ترث صفات القاعدة المورِّثة
وتعدل ما تشاء منها. تمكّن هذه الخاصية المبرمجين من إنشاء قواعد جديدة
مبنية على غيرها وتمكّن أيضا من إنشاء قوالب قواعدية.
-
التصميم الحزمي للقواعد (modular): تحتوي قواعد لغة الأسُس إمكانية إنشاء
حزم من القواعد لتجميع القواعد المترابطة في حزمة واحدة وتسهيل الإشتقاق.
على سبيل المثال، كل القواعد المرتبطة بالتراكيب مجموعة في حزمة واحدة
يسهل الإشتقاق منها لإنشاء تراكيب مخصصة.
توفر هذه الخواص في قواعد لغة الأسُس الإمكانية لإنشاء قواعد أساسية شمولية تُبنى
عليها قواعد اللغة الأخرى بما يَضمن تناسق القواعد المُنشأة من قبل الفرق
المستقلة العاملة على تطوير اللغة.
القواعد الأساسية في لغة الأسُس
مُبسّطة وشمولية وهي تطابق التعريف الشامل لبرنامج الحاسوب كما يلي:
- البرنامج: هو مجموعة من الجمل.
- الجملة: تتكون من حد أو مجموعة متتالية من الحدود.
- الحد: أما قيمة ثابتة أو اسم متغير أو تركيب أو أمر أو جملة أو مجموعة من الجمل.
- الأمر: يتكون من كلمة متبوعة اختياريا بحد أو مجموعة متتالية من الحدود.
- التركيب: يتكون من حد واحد، أو ترابط هرمي من الحدود والمؤثرات.
بالإضافة إلى الترتيب الهرمي أعلاه، تحتوي قواعد لغة الأسُس على
مبدّلات وهي
إضافات يمكن أن تطبّق على أي جزء من الأجزاء المذكورة أعلاه. تستخدم المبدّلات
لإضافة بيانات وصفية (metadata) لأي جزء من أجزاء البرنامج.
تلاحظ من التعريف أعلاه أن القواعد الأساسية لا علاقة لها بطبيعة البرنامج أو البيئة
التي يعمل بها، فهي لا تربط اللغة بمجال محدد بل تتركها مفتوحة على كل المجالات
البرمجية. القلب لا يفهم إلا مجموعة بسيطة من القواعد المخصصة، منها أوامر تحميل
المكتبات (import). عند تحميل مكتبات البناء تغذي هذه المكتبات القلب بقواعدها
المشتقة من القواعد الأساسية وتبقى مسؤولة عن معالجة البيانات المُعربة الناتجة
عن تلك القواعد. وتلقائيا يقوم القلب بربط القواعد الجديدة بتلك المكتبات ويقوم
باستدعائها أثناء الإعراب كلما صادف تلك القواعد. ويستطيع القلب تحميل عدد غير
محدد من تلك المكتبات ويقوم بمهمة التنسيق بينها.
تقنيات القواعد والتحليل
تعتمد قواعد لغة الأسُس، بالإضافة إلى الأساليب التقليدية في كتابة القواعد وإنشاء
المعرِبات، على التقنيات التالية:
اعتماد البيانات في التعريفات القواعدية
يمكن للتعريفات القواعدية أن تعتمد على البيانات عن طريق متغيرات تُعرف ضمن
القاعدة أو ضمن الحزمة. المثال التالي يبيّن تعريف أمر مع ترك الكلمة
التمييزية (keyword) متغيرة:
SubCmd (kwd:string) : kwd Expression
IfCommand : SubCmd("if") Statement.
WhileCommand : SubCmd("while") Statement.
في المثال التوضيحي أعلاه، تجد أن تعريف SubCmd يستقبل سلسلة محارف كمعطى
ويستعملها كثابت في التعريف، وتم استخدام هذا التعريف لتعريف أمري if و while.
الأمر لا يقتصر على استخدام المتغيرات كثوابت في التعريف القواعدي، بل يتعداها
إلى امكانية استخدام المصفوفات وتطبيق العمليات القواعدية على عناصر تلك
المصفوفات. على سبيل المثال:
BinaryOperation (kwds:list[string]) : Operand (kwds[0] | kwds[1] | ...) Operand.
LogicalOperation : BinaryOperation(["and", "or", "xor"]).
MathOperation : BinaryOperation(["+", "-", "*", "/"]).
طريقة استخدام البيانات غير محددة، بل مفتوحة على كل الاحتمالات كما في استخدام
البيانات في لغات البرمجة. على سبيل المثال يمكن تطبيق عناصر المصفوفة على قالب
معين وتطبيق العمليات القواعدية عليها كما في المثال:
BinaryOperation (kwds:list[string]) : Operand (Command(kwds[0]) Command(kwds[1]) ...).
هذه الخاصية تفيد في تسهيل التوريث القواعدي بجعل ما قد يُعدل ضمن حزمة وارثة
معرفًا كمتغيرات، خصوصا عندما تكون هذه المتغيرات مستخدمة في أكثر من قاعدة.
مثلا، لو كان في الحزمة القواعدية عدة تعريفات تستخدم متغيرًا للكلمة
المفتاحية "if" وأردت الاشتقاق من تلك الحزمة لتغيير الكلمة المفتاحية
إلى "If" بدلا من "if" فكل ما تحتاج لتعديله في الحزمة الوارثة هو المتغير.
التصميم الحزمي للقواعد
بالأمكان تجميع التعريفات القواعدية في حزم بطريقة مشابهة للبرمجة كائنية المنحى.
في المثال التالي نقوم بجمع التعريفات المتعلقة بالتراكيب في حزمة واحدة:
Expression : {
Add (kwds=["+","-"]) : Multiply [(kwds[0] | kwds[1] | ...) Add].
Multiply (kwds=["*","/"]) : Operand [(kwds[0] | kwds[1] | ...) Multiply].
Operand : Identifier | Literal.
}.
بالإمكان تعريف حزم داخل أخرى وبالإمكان لقواعد داخل حزمة معينة الإشارة إلى
قواعد خارجها والعكس جائز أيضاً.
التوريث القواعدي
يمكن في قواعد لغة الأسُس استخدام التوريث لاشتقاق قاعدة من قاعدة أخرى. كما هو
حال التوريث في البرمجة كائنية المنحى، فإن التوريث في قواعد الأسُس ينسخ صفات
القاعدة المورِّثة إلى القاعدة الوارثة والتي بدورها تستطيع استبدال بعض هذه
الصفات. على سبيل المثال، لو كان عندنا القاعدة التالية:
LogicalOperation (kwds=["and", "or"]) : Operand (kwds[0] | kwds[1] | ...) Operand.
فيمكن اشتقاق قاعدة أخرى منها تعرف مزيداً من الكلمات التمييزية، كما يلي:
MyLogicalOperation -> LogicalOperation (
kwds = ["and", "or", "&&", "||"]
).
الاشتقاق جائز أيضاً مع الحزم، أي يمكن اشتقاق حزمة من حزمة أخرى. في حالة الحزم
فإن عناصر الحزمة المورِّثة ستنتقل كاملة إلى الحزمة الوارثة التي ستستطيع
استبدال بعض العناصر أو إضافة عناصر أخرى. في المثال التالي نقوم بتعريف حزمة
تشتق من حزمة أخرى وتغيّر أحدى القواعد فيها:
MyExpression -> Expression {
Operand : Identifier | Literal | "(" Add ")".
}.
الإعراب متعدد الأبعاد
الإعراب متعدّد الأبعاد يعني إمكانية تعريف قواعد معينة وتمييزها ليتم إعرابها
بشكل موازٍ لعملية الإعراب الرئيسية. بمعنى آخر، يمكن للمُعرِب عند كل خطوة من
خطوات الإعراب الرئيسي الخروج منه لإعراب القاعدة الموازية ومن ثم العودة إلى
النقطة التي كان فيها من الإعراب الرئيسي. الشكل التالي يوضح هذه العملية.
يُستخدم هذا الأسلوب لتيسير تعريف القواعد التي قد تظهر في أي نقطة من البرنامج
مثل المبدّلات على سبيل المثال. المثال التالي يوضّح الفائدة من هذا الأسلوب:
DefStatement : "def" Identifier ":" Identifier.
ParallelStatement : "@" Identifier.
بتعريف ParallelStatement كقاعدة موازية تكون التعريفات التالية كلها جائزة:
@myattribute def myvar : mytype;
def @myattribute myvar : mytype;
def myvar : @myattribute mytype;
بدون خاصية الإعراب متعدّد الأبعاد سنحتاج لتعريف DefStatement كما يلي:
DefStatement : [ParallelStatement] "def" [ParallelStatement] Identifier ":" [ParallelStatement] Identifier.
مبادئ تصميمية
هناك مبادئ عامة وضعت بعين الإعتبار في تصميم وتنفيذ لغة الأسُس، ويُطلب من مطوري
مكتبات لغة الأسُس مراعاتها. في هذه القائمة كلمة مبرمج تشير إلى مستخدم اللغة،
وليس إلى مطورها.
-
إستقلال القواعد عن السياق: يجب على قواعد اللغة أن تكون مستقلة عن سياق
البرنامج، بمعنى آخر يجب على المعرِب (parser) أن يتمكن من إعراب الشفرة
المصدرية دون الحاجة لمعرفة ما تعنيه تلك الشفرة أو بعض مفرداتها.
-
تجنب الزوائد القواعدية: على سبيل المثال لا حاجة لفرض استخدام الأقواس إن
كان بالإمكان تحليل الشفرة دون أقواس.
-
تناسق القواعد والتصميم: يجب الحفاظ على التناسق في القواعد وفي تصميم
المكتبات.
-
منطقية القواعد على حساب الجمالية أو العرف السائد: لسنا بحاجة للإلتزام
بما هو شائع بين لغات البرمجة، فالحفاظ على منطقية القواعد أهم من جماليتها
أو عادات المبرمجين.
-
ليس هناك معايير قياسية في تصميم لغات البرمجة، لكن هناك معايير قياسية في
كتابة الرياضيات سائدة منذ مئات السنين، لذا فمشابهة المعايير الرياضية أولى
شرط عدم الإخلال بمنطقية القواعد. على سبيل المثال الدوال في الرياضيات تكتب
باستخدام الأقواس الاعتيادية وبالتالي فالدوال في لغة الأسُس تكتب أيضاً باستخدام
الاقواس الاعتيادية.
-
تقليص الإعتماد على قواعد جديدة: كلما كان تصميم القواعد أكثر شمولية، قلت
الحاجة لتصميم قواعد جديدة.
-
تعامد الخصائص والتصميم الحزمي: الحفاظ قدر الإمكان على تعامد
الخصائص (orthogonality) والتصميم الحزمي (modular design).
-
تمكين المبرمج من العمل على كافة المستويات بدءًا من التحكم المباشر بالعتاد
وانتهاءًا بأعلى مستويات البرمجة.
-
الحفاظ على مستوى واحد داخل المكتبة الواحدة: عند تصميم المكتبات المعيارية
يجب تجنب الخلط بين المستويات داخل المكتبة الواحدة.
-
دعم الخواص بأخفض مستوى ممكن: كلما كانت الخاصية متوفرة بمستوى منخفض أكثر
كلما توسع نطاق توفرها.
-
تجنب اتخاذ خطوات وقرارات نيابة عن المبرمج: يجب أن يعلم المبرمج كيف سيتم
التعامل مع برنامجه من قبل نظام الترجمة. على سبيل المثال، من غير الملائم
أن تقرر مكتبة البناء أسلوب إدارة الذاكرة دون إعطاء المبرمج القدرة على
التحكم بذلك القرار.
-
تجنب الحدود المصطنعة: على سبيل المثال، لا تحرم المبرمج إمكانية استخدام
المؤشرات المباشرة في سياق معين إذا كان استخدامها ممكناً في ذلك السياق.
حرمان المبرمج من خاصية معينة فقط لأن هذه الخاصية قد يُساء استخدامها عذر
غير مقبول.
المكتبات المعيارية
يستطيع القلب تمييز ثلاث أنواع من الملفات عند شمولها باستخدام
الأمر `اشمل` (`import`):
-
مكتبات ديناميكية: هي المكتبات الرقمية، أي المبنية مسبقًا. القلب يحمل
هذه المكتبات لكنه لا يتعامل معها بأي شكل من الأشكال.
-
مكتبات البناء: وهي مكتبات ديناميكية لكنها تحتوي على واجهة معينة
يميزها القلب عند تحميلها فيستدعي دالة التهيئة فيها لتضيف قواعدها
ومعالجات البناء الخاصة بها. تستخدم هذه المكتبات للإضافات التي تتطلب
تعاملًا مفتوحًا مع كافة وحدات القلب، مثل إضافة نمط برمجة كامل.
-
ملفات مصدرية: وهي الملفات المكتوبة بلغة الأسس والتي يُترجمها القلب عند
تحميلها ثم ينفذها.
تشمل المكتبات المعيارية للغة الأسس:
-
مكتبة نمط البناء المعياري (Standard Programming Paradigm):
هي مكتبة بناء تحتوي القواعد ومعالجات البناء اللازمة لتوفير البرمجة
الإجرائية (procedural programming).
-
مكتبة التنفذي المعيارية (Standard Runtime Library):
وهي المكتبة التي تحتوي على مجموعة دالات وأصناف أساسية
يستعملها البرنامج أثناء التنفيذ مثل مكتبات الدالات الرياضية أو مكتبات
التعامل مع سلاسل المحارف.
-
مدير حزم الأسس (Alusus Package Manager):
هي مكتبة توفر إمكانية تنزيل مكتبات أخرى من الشبكة العنكبوتية مباشرة
ثم شمولها في برنامج المستخدم.
-
مغلفة (closure): مكتبة لتوفير خاصية الدالات المغلفة (closures).
-
بـناء (Build): مكتبة لتمكين إنشاء ملفات تنفذية من مشروع المستخدم.
مكتبة نمط البناء المعياري (Standard Programming Paradigm)
هذه أهم مكتبة من مكتبات الأسس وهي توفر نمط البرمجة الإجرائية بالإضافة إلى البرمجة
الكائنية وبدونها لا يمكن للمترجم تمييز وتنفيذ البرامج. وهي تعتمد على LLVM لإنشاء
الشفرة التنفيذية النهائية. تحتوي هذ المكتبة على الكثير من الأصناف بداخلها ويمكن
تقسيم هذه الأصناف إلى المجموعات التالية:
- AST: أصناف شجرة البنية المجردة التي تستخدمها المكتبة في قواعدها الخاصة.
- Handlers: أصناف معالجات البناء الخاصة بالمكتبة.
- CodeGen:
الأصناف التي تعمل على تحويل البرنامج من صيغة AST إلى الصيغة
التي يفهمها منشئ شفرة تنفيذية منخفص المستوى مثل LLVM.
- LlvmCodeGen: الأصناف التي تمثل حلقة الوصل بين المكتبة وLLVM.
بالإضافة لهذه المجموعات تحتوي المكتبة على أصناف إساسية لإدارة عملية الترجمة
والتنفيذ.
توفر هذه المكتبة الخصائص التالية:
- الأصناف الأساسية المنخفضة المستوى.
- البرمجة الإجرائية وما يتعلق بها من دالات وجمل شرطية وغيرها.
- أصناف المستخدم
- اللبنات الاساسية للبرمجة الكائنية.
- قوالب الأصناف والدالات.
- الماكروهات.
- الوحدات.
توفر المكتبة ثلاث مستويات من الترجمة والتنفيذ:
-
التنفيذ المباشر (Just-in-Time): عندما يمر المترجم على شفرة خارج الدالات (مثلا
في المجال الرئيسي) يترجمها مع اعتمادياتها من أصناف ودالات ثم ينفذها مباشرة.
-
التنفيذ التمهيدي (preprocess) أو التنفيذ أثناء الترجمة: توفر المكتبة قواعد
خاصة لتحديد شفرة محددة تُنفذ أثناء ترجمة الدالات والأصناف، وهذا يتيح للمستخدم
إنشاء شفرة جديدة وإضافتها للدالة أو الصنف قيد الترجمة.
-
الترجمة غير الحية (offline): توفر المكتبة إمكانية الترجمة عند الطلب لأي جزء
من الشفرة المصدرية. في هذه الحالة يُترجم العنصر إلى شفرة تنفيذية تُخزن في ملف
بدل أن تُنفذ.
نظرة على القواعد
فيما يلي نماذج لقواعد اللغة المُضمّنة في المكتبات المعيارية. هذه النماذج تمثل
نبذة مختصرة ولا تتضمن كل تفاصيل القواعد.
التراكيب
تتكون التراكيب من حدود تربطها مؤثرات (operators) بشكل مشابه للّغات الشائعة
الأخرى. وفيما يلي قائمة بأهم المؤثرات المتوفرة:
مؤثر النفي: !
مؤثر أو: |
مؤثر أو حصرية (xor): $
مؤثر و: &
العمليات الحسابية: +، -، *، /
العمليات البِتّية (bitwise): &، |، $, !
العمليات المنطقية: &&، ||، $$، !!
المقارنات: <،>، =>، = <،==,=!
التعيين: =
العمليات التعيينية: =+، =-، =*، =/، =|، =&، =$
القوائم تُفصل بالفاصلة. على سبيل المثال: a,b,c
تجميع الحدود يتم باستخدام الأقواس الإعتيادية: ()
الحلقات
لـكل: "لكل" الـتركيب_الـاستهلالي "،" الـتركيب_الـشرطي "،" تـركيب_الـتحديث (جـملة|كـتلة).
بـينما: "بينما" تـركيب (جـملة|كـتلة).
افـعل-بـينما: "افعل" (جـملة|كـتلة) "بينما" تـركيب.
For: "for" Initial_Expression "," Condition_Expression "," Update_Expression (Statement|Block).
While: "while" Expression (Statement|Block).
Do-While: "do" (Statement|Block) "while" Expression.
الجمل الشرطية
"إذا" تـركيب (جـملة|كـتلة) ["وإلا" (جـملة|كـتلة)].
"if" Expression (Statement|Block) ["else" (Statement|Block)].
التعريفات
كل التعريفات في اللغة تتم باستخدام أمر `عرف` (`def`) بما في ذلك تعريف متغيرات أو ثوابت
أو دالّات أو أصناف أو غيرها. كما توفر الدالات والأصناف والوحدات صيغة مختصرة
للتعريفات باستخدام الكلمة المفتاحية الخاصة بكل منها. صيغة الأمر `عرف` (`def`) كالتالي:
"عرف" اسم ":" متن.
"def" name ":" body.
قيمة body يمكن أن تكون دالّة أو صنفا أو مجالا أو أسم صنف أو غيرها وذلك
موضح فيما يلي:
تعريف متغير:
"عرف" اسم ":" صنف.
"def" name ":" type.
تعريف ثابت:
"عرف" اسم ":" قيمة.
"def" name ":" value.
تعريف دالة:
"عرف" اسم ":" "دالة" "(" قـائمة_الـمدخلات ")" "=>" الـناتج كـتلة.
"def" name ":" "function" "(" Input_List ")" "=>" Output Block.
وباستخدام الصيغة المختصرة:
"دالة" اسم "(" قـائمة_الـمدخلات ")" "=>" الـناتج كـتلة.
"function" name "(" Input_List ")" "=>" Output Block.
تعريف قالب دالة:
"عرف" اسم ":" "دالة" "[" قـائمة_مدخلات_القالب "]" "(" قـائمة_الـمدخلات ")" "=>" الـناتج كـتلة.
"def" name ":" "function" "[" Template_Arg_List "]" "(" Input_List ")" "=>" Output Block.
وباستخدام الصيغة المختصرة:
"دالة" اسم "[" قـائمة_مدخلات_القالب "]" "(" قـائمة_الـمدخلات ")" "=>" الـناتج كـتلة.
"function" name "[" Template_Arg_List "]" "(" Input_List ")" "=>" Output Block.
تعريف صنف:
"عرف" اسم ":" "صنف" كـتلة.
"def" name ":" "class" Block.
وباستخدام الصيغة المختصرة:
"صنف" اسم كـتلة.
"class" name Block.
تعريف قالب صنف:
"عرف" اسم ":" "صنف" "[" قـائمة_مدخلات_القالب "]" كـتلة.
"def" name ":" "class" "[" Template_Arg_List "]" Block.
وباستخدام الصيغة المختصرة:
"صنف" اسم "[" قـائمة_مدخلات_القالب "]" كـتلة.
"class" name "[" Template_Arg_List "]" Block.
تعريف حزمة:
"عرف" اسم ":" "حزمة" كتلة.
"def" name ":" "module" Block.
وباستخدام الصيغة المختصرة:
"حزمة" اسم كتلة.
"module" name Block.
ويستخدم إيعاز `عرف` (`def`) أيضا لكافة التعريفات الأخرى ومن بينها المصفوفات
والمؤشرات المبينة أدناه.
المصفوفات
تعرّف المصفوفات باستخدام أمر def وبالشكل التالي:
"عرف" اسم ":" "مصفوفة" "[" صنف، رقم "]".
"def" name ":" "array" "[" type, number "]".
استخدام المصفوفات:
اسم "(" رقم ")".
name "(" number ")".
المؤشرات
تعّرف المؤشرات باستخدام أمر def أيضا وبالشكل التالي:
"عرف" اسم ":" "مؤشر" "[" صنف "]".
"def" name ":" "ptr" "[" type "]".
وللدخول إلى الموقع الموُشَّر يستخدم مؤثر cnt~ بعد اسم المؤشر:
اسم "~محتوى".
name "~cnt".
وللحصول على موقع متغير معين يستخدم مؤثر ptr~ بعد اسم المتغير:
اسم "~مؤشر".
name "~ptr".
التعريفات المتداخلة
يمكن أيضا الدمج بين التعريفات باستخدام def. مثلا يمكن تعريف مؤشر على
مصفوفة، أو مؤشر على دالة, أو مصفوفة من المؤشرات، إلى أخره. مثلا تعريف
مصفوفة من مؤشرات الدالّات يتم بالشكل التالي:
"عرف" اسم ":" "مصفوفة" "[" "مؤشر" "[" "دالة" "(" مـدخلات ")" "]" "]".
"def" name ":" "array" "[" "ptr" "[" "function" "(" Params ")" "]" "]".
الدمج بين التعريفات
يمكن دمج تعريف مع تريف مسبق بنفس الأسم باستخدام الأمر عرف (def) مع المبدل
@دمج (@merge). الدمج جائز مع الحزم (module) ومع أصناف المستخدم (type)
ويكون بالشكل التالي:
"@دمج" "عرف" اسم ":" "حزمة" "{" تـعريفات "}".
"@دمج" "عرف" اسم ":" "{" تـعريفات "}".
"@merge" "def" name ":" "module" "{" Definitions "}".
"@merge" "def" name ":" "{" Definitions "}".
المبدّلات
يمكن للمبدّلات أن تظهر في أي مكان في البرنامج وليس بالضرورة في بداية
الجملة. وتعرّف المبدّلات بهذا الشكل:
"@" اسم "[" تـركيب "]".
"@" name [ Expression ].
الأقواس الهلالية والأقواس المعقوفة
تستخدم الأقواس الهلالية في الأمور التي تُعالج أثناء تنفيذ البرنامج مثل جمع
الحدود داخل التراكيب أو إرسال المدخلات إلى الدالّات، بينما تستخدم الأقواس
المعقوفة في الأمور التي تُعالج أثناء الترجمة مثل تحديد نوع المؤشر أو
المصفوفة. بمعنى آخر، إن كانت المعلومة مرسلةً إلى المترجم نفسه تُسخدم
الأقواس المعقوفة، وإلا فالأقواس الهلالية.
الأقواس الحاصرة {}
تستخدم الأقواس الحاصرة لحصر مجموعة من الجمل في كتلة واحدة. وتستخدم هذه
الكتل في جواب الجمل الشرطية على سبيل المثال أو في متن الدالّات أو الأصناف
أو المجالات.
كـتلة: "{" [ مـجموعة_جـمل ] "}".
مـجموعة_جـمل: جـملة { "؛" [جـملة] }.
Block: "{" [ Statement_List ] "}".
Statement_List: Statement { ";" [Statement] }.
الفصل بين الجمل
تستخدم الفاصلة المنقوطة للفصل بين الجمل بطريقة مشابهة للفاصلة الإعتيادية
التي تفصل بين الحدود داخل القوائم. بمعنى آخر فإن الفاصلة المنقوطة ليست
جزءاً من الجملة ويُمكن إهمالها إن لم يأت بعدها جملة أخرى.
المنطق في بعض الخيارات النحوية
-
أقواس الدالّات:أُستخدمت الأقواس الاعتيادية مع الدالّات في الرياضيات منذ
القدم، لذا تم الالتزام بذات الاسلوب مع دالّات لغة الأسُس.
-
معطيات الأوامر: معطيات الأوامر (مثل فعل الشرط في الجمل الشرطية) تخلوا
من الأقواس ببساطة لأنها لا حاجة لها من منظور إعرابي لذا فإن إضافتها لا
معنى له.
-
يُفضل البعض البرامج بدون علامة الفصل بين الجمل (;) ولكن إن كان الأمر
صحيحاً فلماذا لدينا تنقيط في اللغات البشرية؟
-
عوملت الكلمات الترميزية public و private وما شابههما كمبدّلات (أي
ببدئهم بالرمز @) لأنهم ببساطة ليسوا أكثر من معلومات وصفية يستخدمها
نظام الترجمة لكنها ليست عمليات تؤثر على طريقة تنفيذ البرنامج.
-
التعريفات تبدأ دائمًا بكلمة مفتاحية يليها اسم المُعرَّف ولا يسبق اسم
المُعرَّف شيء سوى الكلمة المفتاحية وذلك لحصر كامل التعريف في الجهة
التي تلي الاسم بدل أن يكون اسم المعرف ضائعًا في وسط الجملة كما هو
الحال على سبيل المثال في تعريفات الدالات في لغة السي. يساعد هذا
الأمر على تيسير فهم التعريفات خصوصاً مع التعريفات المركبة مثل
تعريف مؤشر إلى دالّة أو مصفوفة مؤشرات إلى دالّات.
-
استخدمت الأقواس الهلالية للولوج إلى عناصر المصفوفة بدل الأقواس المعقوفة
لأن الأخيرة تستخدم لمعطيات الترجمة. ولنفس السبب استخدمت الأقواس
الاعتيادية لتحديد حجم المصفوفة ديناميكياً بينما استخدمت الأقواس
المعقوفة لتحديد نوع المصفوفة وهو ما يندرج ضمن معطيات الترجمة.