محمد علاء الدين

[++C] وحدات اللغة

1 مشاركة في هذا الموضوع

بسم الله الرحمن الرحيم

 

عند تمرير كود للمترجم، فأول ما سيفعله هو تقسيم الكود إلى نصوص صغيرة - سنطلق عليهم وحدات - ثم يقوم بتحديد طبيعة كل نص بناءاً على محتوى ذلك النص. عملية التقسيم تسمى Tokeninzing و النص الواحد يسمى Lexeme. يقوم المترجم بإعطاء كود لكل مجموعة من النصوص المتجانسة و يسمى Token. اللغتان C++/C تختلفان عن العديد من اللغات الأخرى بأن لهما نوعين من الـ Tokens و هما محور هذا الموضوع.

فى هذا الموضوع[1]




وحدات Preprocessor

المعالج Preprocessor له لغة خاصة به تختلف عن اللغتين C++/C، و يمكنك القول أن الهدف منها هو تنسيق و تهيئة الكود المدخل له حتى تستطيع وحدة المترجم (التى تقوم بالتحقق الفعلي من الكود) البدء فى عملها. هذه اللغة - و التي سيتم شرحها فى الموضوع القادم بإذن الله - تقوم بتقسيم الكود المدخل لها إلى وحدات صغيرة Tokens تستطيع فهمها و التعامل معها، هذه الوحدات يفهمها المعالج فقط و إذا حدث أن رآها المترجم فسيعتبر العديد منها خطأً لغويّاً.

و حيث أن هذه الوحدات يتم التعامل معها فقط من خلال وحدة المعالج فمن هنا جاء اسمها و هو Preprocessor Tokens.

عندما يبدأ المعالج عمله فإنه يقوم بتنفيذ مراحل الترجمة[2] من الخطوة الأولى و حتى الرابعة، في هذا الموضوع سنركز جهودنا في فهم الخطوات الثلاثة الأولى[3].

عملية المعالجة لها بعض الخصائص:

  • عملية المعالجة تعتمد على السياق فمثلا:
    <::type2>
    بعد معالجتها ستنتج:
    <::type2>
    مع العلم أن :> تشكل معاملاً موجوداً و لكن لأن الـ colon تبعتها colon أخرى تم فصل > عن ::
    أيضاً عملية استخراج النصوص تعتمد على السياق فمثلاً داخل النص إذا وجدت double-quotes فلن يتم التعامل معها على أنها نهاية للنص و لكن كجزء منه.
  • يتم الحصول على أطول قيمة تمثل وحدة معينة فمثلا يوجد المعامل + و أيضاً المعامل =+، لذا عند الحصول على + لا يتم التوقف حتى تصبح القيم التي لدينا توافق وحدة preprocessing-token معلومة.




الملاحظات comments

مشروحه فى 2.7، الملاحظات لها نوعان:

  • ملاحظات السطر الواحد: و هي تبدأ بـ // و تنتهي بالسطر الجديد.
  • ملاحظات بأكثر من سطر: و هي تبدأ بـ */ و تنتهي بـ /*

للملاحظات بعض الخصائص:

  • الملاحظات لا تتداخل و هذا يعني أن وجود نمط داخل آخر لا يؤثر عليه، فمثلاً لو وجد نمط السطر الواحد فإنه ينتهي بنهاية السطر حتى لو كان داخله بداية لنمط ملاحظات الأكثر من سطر.
  • كافة محتويات الملاحظات يتم تجاهلها و تحويلها لمساحة فارغة أو أكثر (هذا بالإضافة للعلامة التي تحدد وجود الملاحظة).




الـ header-name

مشروح فى 2.8، هو النص الذي يتم استخدامه مع include# و لابد أن يكون أحد الأشكال التالية:

<h-char-sequence>"q-char-sequence"pp-tokens

حيث:

h-char-sequence:	h-char	h-char-sequence h-charh-char:	any member of the source character set except new-line and >q-char-sequence:	q-char	q-char-sequence q-charq-char:	any member of the source character set except new-line and "

السابق هو الصيغة التي لابد أن يكون عليها شكل header-name أثناء معالجته، هذه الصيغه تراجعية Recursive و لفهمها لا يوجد أفضل من مثالين أحدهما صحيح و الآخر خاطئ.

في المثال الصحيح، سنفترض وجود السطر التالي داخل الكود:

#include <iostream>

عندما يرى المعالج ذلك السطر فإنه يقرأ # كأول حرف في السطر و بهذا يعلم أن هذا السطر يحتوي على أمر للمعالج و بعدها يرى الكلمة include و بهذا يعرف أن ما يليها هو header-name ثم يبدأ في مقارنة المحتويات و لأن أول حرف هو > فإنه يعلم أن الصيغة:

<h-char-sequence>

هي أساس المقارنة، و هذا يعني أن المترجم الآن سيبدأ مطابقة الكلمة iostream مع h-char-sequence و التي تعني وجود h-char واحد أو أكثر، h-char نفسها شرحها:

any member of the source character set except new-line and >

و هذا يعني أن أي حرف مسموح به داخل هذه الصيغة ماعدا السطر الجديد و العلامة < لأنها علامة انتهاء header-name فإن تم إستخدامها داخل النص فسيتم اعتبارها نهاية نص الـ header-name و البقية ستسبب خطأ أثناء المعالجة.

المثال الحالي سيتم مطابقته كالتالي:

<iostream>< match start h-char-sequencei match h-char, continue scano match h-char, continue scans match h-char, continue scant match h-char, continue scanr match h-char, continue scane match h-char, continue scana match h-char, continue scanm match h-char, continue scan'>' is invalid h-char, stop scan> match end h-char-sequencecode is valid

لنأتي للمثال الخاطئ:

#include <iostream// comment

سيتم معالجته كالتالي:

#include <iostream< match start h-char-sequencei match h-char, continue scano match h-char, continue scans match h-char, continue scant match h-char, continue scanr match h-char, continue scane match h-char, continue scana match h-char, continue scanm match h-char, continue scannew-line is invalid h-char, stop scannew-line matched before >, stop scancode is invalid

أعتقد أن الصيغة أصبحت مفهومة بشكل أفضل. و للاختصار فهذه الصيغة يتم تنفيذها بشكل رجعي حتى يصبح شرط التكرار - في حالتنا هذه المشروح داخل h-char أو q-char - خاطئ.

الصيغة q-char-sequence تستخدم double-quotes كعلامة لبدء header-name و يتم استخدام q-char كشرط لمطابقة محتويات الـ header-name.

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

الصيغة الأخرى pp-tokens تعني استخدام ماكرو بدلاً من الصيغتين الأخريين و عندما يتم تنفيذ الماكرو سيتم إبداله بالقيمة المناسبة و التي إن كانت غير صحيحة فسينتج undefined-behavior، مثال:

#ifdef OLD_COMPILER#  define LIB_NAME <iostream.h>#else#  define LIB_NAME <iostream>#endif#include LIB_NAMEusing namespace std;

إذا كان الثابت OLD_COMPILER معرفاً فإنه سيتم استخدام المكتبة iostream.h بدلاً من iostream.




المعرفات identifiers

هي الكلمات التي يتم إستخدامها لإعطاء اسم لأي شيء داخل اللغة. المعرف لابد أن يطابق الصيغه التالية:

identifier:	nondigit	identifier nondigit	identifier digitnondigit: one of	universal-character-name	_ a b c d e f g h i j k l m	n o p q r s t u v w x y z	A B C D E F G H I J K L M	N O P Q R S T U V W X Y Zdigit: one of	0 1 2 3 4 5 6 7 8 9

المعرف يبدأ بأحد عناصر nondigit يليه صفر أو أكثر من nondigit/digit/universal-character-name، و صفر أو أكثر تعني أن المعرف قد يكون حرفاً واحداً على الأقل , و أقصى عدد من الحروف التي تمثل المعرف يتم تحديدها من قبل المترجم.

توجد بعض القيود عند تصميم المعرفات بعضها يطبّق في مرحلة المعالجة و الآخر في مرحلة الترجمة[4]:

  • المعرفات حساسة تجاه حالة الأحرف، فالحرفان a و A مختلفان. مشروح فى 2.10.1.
  • المعرفات التي تتطابق مع الكلمات المحجوزه باللغة - مثل new أو mutable - محجوزة لمترجم اللغة لوصف بناء معين - مشروح فى 2.11 - و في مرحلة المعالجة يفضل ألا يتم استخدامها كماكرو حيث إن وجدهم المعالج قد يتم استبدالها بأخرى - مشروح فى 17.4.3.1.1.2، مثلاً
    // before preprocessor#define new "string"int* arr = new int[10];// after preprocessorint* arr = "string" int[10];
    مثل هذه الأخطاء يصعب معرفة سببها لأن الكود يظهر الكلمه new اما النسخه التى يراها المترجم فهى النص "string"، بالتأكيد هذا المثال واضح أما في البرامج الحقيقية فتصبح العملية أسوأ بكثير.
  • الحروف التى يتم كتابتها باستخدام universal-character-name لابد أن توافق[5] معاييرISO 10646 و أن تقع فى مدى الحروف المسموح به و المشروح فى Annex E.
  • يوجد مدىً من الحروف يمنع استخدامه بواسطة universal-character-name لوجوده داخل basic source character set و هو فى المدى 0x0041-0x005A و 0x0061-0x007A.
  • أسماء الماكرو المعرفة من قبل مصممي مكتبات اللغة داخل هذه المكتبات محجوزة لهم و يفترض بمبرمج اللغة ألا يقوم بتسمية ماكرو بنفس هذه الأسماء داخل ملفات الكود الخاصه به أو أن يقوم بحذفهم باستخدام undef# و إن حدث فهذا ينتج undefined-behavior.
  • المعرفات التى تبدأ بـ underscore أو تبدأ باثنين من underscore محجوزة[6] للاستخدام من قبل مصممي مكتبات اللغة داخل مجال الأسماء العام[7]. مشروح فى 17.4.3.1.2.
  • في مرحلة الترجمة داخل مكتبات اللغة أي معرف مستخدم لمتغير أو لدالة و تم تحديده بالكلمة extern سواء كانت لـ "C" أو لـ "++C" محجوز لوصف ما يشير إليه و بالنسبة للدوال فبصمتها أيضاً محجوزةٌ لتلك الدالة. هذه المعرفات محجوزة في مجال الأسماء العام أو في مجال الأسماء std. مشروح فى 17.4.3.1.3.




أرقام المعالجة pp-number

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

الصيغة التي يتم مطابقتها كالتالي:

pp-number:	digit	. digit	pp-number digit	pp-number nondigit	pp-number e sign	pp-number E sign	pp-number .digit: one of	0 1 2 3 4 5 6 7 8 9nondigit: one of	universal-character-name	_ a b c d e f g h i j k l m	n o p q r s t u v w x y z	A B C D E F G H I J K L M	N O P Q R S T U V W X Y Zsign: one of	- +

س. لماذا يتم وضع كافة الحروف الأبجدية و universal-character-name داخل صيغة الرقم، أليست الأرقام المعرفة باللغة لها صيغة محددة؟

سؤالك فى محله لو أن الرقم الناتج استخدمناه كرقم فقط , فمثلا انظر للكود التالي:


// before preprocessing#define CREATE(X) int ID_##X;CREATE(12AA21)// after preprocessingint ID_12AA21;

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

حيث أن الأرقام في مرحلة المعالجة قد تحتوى على أرقام و حروف بالتالي هذه الأرقام لا نوع لها[8].




الحروف character-literal

مشروح فى 2.13.2، سلسلة تتكون من حرف أو أكثر و تحاط بالعلامة single quotes. الصيغة التي تستخدم لوصف القيمة الحرفية هي:

character-literal:	'c-char-sequence'	L'c-char-sequence'c-char-sequence:	c-char	c-char-sequence c-charc-char:	any member of the source character set except the single-quote ', backslash \, or new-line character	escape-sequence	universal-character-namehexadecimal-digit: one of	0 1 2 3 4 5 6 7 8 9	a b c d e f	A B C D E Foctal-digit: one of	0 1 2 3 4 5 6 7hex-quad:	hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digitescape-sequence:	simple-escape-sequence	octal-escape-sequence	hexadecimal-escape-sequencesimple-escape-sequence: one of	\' \" \? \\ \a \b \f \n \r \t \voctal-escape-sequence:	\ octal-digit	\ octal-digit octal-digit	\ octal-digit octal-digit octal-digithexadecimal-escape-sequence:	\x hexadecimal-digit	hexadecimal-escape-sequence hexadecimal-digituniversal-character-name:	\u hex-quad	\U hex-quad hex-quad

القيمة الحرفية أو السلسلة الحرفية لها بعض الخصائص:

  • تتكون من حرف أو أكثر محاط بالعلامة single-quote كما في 'x'.
  • عندما تحتوى على حرف واحد تسمى قيمة حرفية character literal و عندما تحتوى على أكثر من حرف تسمى سلسلة حرفية multi-character literal.
  • قد يسبقها الحرف L او لا يسبقها شيء مثل 'x' و 'L'x كلاهما مثال صحيح على قيمة/سلسلة حرفية.
  • القيمة/السلسلة الحرفية التى لا يسبقها شيء تسمى بـ ordinary character literal، وأيضاً تسمى بـ narrow-character literal.
  • القيمة/السلسلة الحرفية التى يسبقها L تسمى بـ wide-character literal.
  • القيمة الحرفية التى لا يسبقها شيء نوعها char و قيمة الحرف الموجود بها يماثل قيمته داخل execution character set.
  • القيمة الحرفية التى يسبقها L نوعها wchar_t و قيمة الحرف الموجود بها يماثل قيمته داخل execution wide-character set.
  • السلسلة الحرفية التى لا يسبقها شئ نوعها int و قيمتها يحددها مصمم المترجم implementation-defined.
  • السلسلة الحرفية التى يسبقها L نوعها wchar_t و قيمتها يحددها مصمم المترجم implementation-defined.

بعض الحروف التي لا شكل لها و single-quote و double-quote و question mark و backslash يمكن استخدامها داخل القيمة/السلسلة الحرفية كالتالي:

┌─────────────────────┬────────────────┬─────────────────────┐│   description       │   name/glyph   │   escape sequence   │├─────────────────────┼────────────────┼─────────────────────┤│   new-line          │   NL (LF)      │      \n             │├─────────────────────┼────────────────┼─────────────────────┤│   horizontal tab    │   HT           │      \t             │├─────────────────────┼────────────────┼─────────────────────┤│   vertical tab      │   VT           │      \v             │├─────────────────────┼────────────────┼─────────────────────┤│   backspace         │   BS           │      \b             │├─────────────────────┼────────────────┼─────────────────────┤│   carriage return   │   CR           │      \r             │├─────────────────────┼────────────────┼─────────────────────┤│   form feed         │   FF           │      \f             │├─────────────────────┼────────────────┼─────────────────────┤│   alert             │   BEL          │      \a             │├─────────────────────┼────────────────┼─────────────────────┤│   backslash         │   \            │      \\             │├─────────────────────┼────────────────┼─────────────────────┤│   question mark     │   ?            │      \?             │├─────────────────────┼────────────────┼─────────────────────┤│   single quote      │   '            │      \'             │├─────────────────────┼────────────────┼─────────────────────┤│   double quote      │   "            │      \"             │├─────────────────────┼────────────────┼─────────────────────┤│   octal number      │   ooo          │      \ooo           │├─────────────────────┼────────────────┼─────────────────────┤│   hex number        │   hhh          │     \xhhh           │└─────────────────────┴────────────────┴─────────────────────┘

الجدول السابق يحتوي على الصيغة التي يمكن استخدامها داخل القيمة/السلسلة الحرفية لوصف الحروف المذكورة بالجدول، و توجد بعض الملاحظات:

  • الحرفان double-qoutes و question mark سواء استخدما كما هما أو باستخدام الـ escape-sequence فالنتيجة واحدة.
  • الحرفان single-quote و backslash حتى يتم التعرف عليهما بشكل صحيح لابد من استخدام نسخة escape-sequence فقط.
  • إذا تم استخدام escape-sequence مع حروف غير الموجودة في الجدول فهذا ينتج undefined-behavior.
  • الصيغة ooo\ تتكون من backslash يليها واحد أو اثنان أو ثلاثة أرقام من النظام الثماني و القيمة الناتجة من هذه الصيغة تستخدم لوصف حرف معين.
  • الصيغه xhhh\ تتكون من backslash يليها الحرف x يليها رقم أو أكثر من النظام السداسي عشر و القيمة الناتجة من هذه الصيغة تستخدم لوصف حرف معين.
  • الصيغة ooo\ او xhhh\ تنتهي مع أول حرف لا يمثل قيمة في النظام الثماني أو السداسي عشر على التوالي.
  • في الصيغة ooo\ او xhhh\ تصبح قيمة الحرف محددة من قبل المترجم implementation-defined إذا تجاوزت قيمة الحرف أقصى قيمة لتمثيله داخل نوع الحرف المحدد سواء كان char أو wchar_t.
  • يتم تحويل صيغة universal-character-name إلى الحرف الذي يماثلها من داخل execution character set و إن لم يجد المترجم الحرف المراد حينها ستصبح قيمة الحرف محددة من قبل المترجم implementation-defined.




النصوص string-literal

مشروح فى 2.13.4، سلسلة فارغة أو تتكون من حرف أو أكثر و تحاط بالعلامة double quotes. الصيغة التي تستخدم لوصف القيمة الحرفية هي:

string-literal:	"s-char-sequence[opt]"	L"s-char-sequence[opt]"s-char-sequence:	s-char	s-char-sequence s-chars-char:	any member of the source character set except the double-quote ", backslash \, or new-line character	escape-sequence	universal-character-name

الكلمه [opt] في آخر مسمى الصيغة تعني أن ذلك المسمى في ذلك المكان اختياري , أي أنه قد يكون موجوداً أو غير موجود.

السلسلة النصية لها بعض الخصائص:

  • الصيغة s-char-sequence اختيارية، و هذا يعنى أنه قد لا يكون هناك أى حروف بين الـ double-quotes.
  • قد يسبقها الحرف L او لا يسبقها شيء مثل "xyz" و "L"xyz فكلاهما مثال صحيح على سلسلة نصية.
  • السلسلة النصية التي لا يسبقها شيء تسمى بـ ordinary string literal، وأيضاً تسمى بـ narrow-string literal.
  • السلسلة النصية التى يسبقها L تسمى بـ wide-string literal.
  • السلسلة النصية التي لا يسبقها شيء نوعها[9]مصفوفة من const char، و التي يسبقها L نوعها مصفوفة من const wchar_t
  • فترة حياة السلسلة النصية تدوم طوال عمل البرنامج[10]، و أي محاولة لتغيير محتويات السلسلة وقت عمل البرنامج تسبب undefined-behavior.
  • في مرحلة الترجمة رقم 6 يتم دمج ordinary string literal المتتالية، وأيضاً يتم دمج wide-string literal المتتالية، إذا وجدت ordinary string literal ثم تبعها wide-string literal أو العكس فعملية الدمج تسبب undefined-behavior.
  • السلاسل النصية التي يتم دمج محتوياتها معاً يتم فصل محتواها , فمثلا النصّان:
    "\xA" "B"
    بعد دمجهم يصبحان "xAB\" و لكن محتويات النص الجديد لن تكون الحرف 'xAB\' و لكن الحرفبن 'xA\' و 'B'.
  • بعد انتهاء كل عمليات الدمج لكل النصوص إن وجدت سيتم إضافة الحرف '0\' لنهاية كل سلسلة نصية لتحديد نهايته.
  • عدد الحروف الموجودة بالسلسة النصية يساوي عدد الـ escape-sequence بالإضافة لعدد الـ universal-character-name بالإضافة لعدد باقي الحروف بالإضافة إلى الحرف '0\'.
  • الـ escape-sequence و الـ universal-character-name يتم التعامل معهما بنفس الأسلوب كما في character-literal مع الفرق أن الـ single-quote يمكن استخدامها بنفسها على العكس مع double-quote التي لابد أن يتم استخدام الـ backslash معها.
  • داخل السلسلة النصية ordinary string literal يمكن للـ universal-character-name أن تتكون من أكثر من حرف و ذلك تبعاً لترميز الحروف الذي يستخدمه المترجم[11].




المعاملات و الرموز preprocessing-op-or-punc

مشروح فى 2.12، هي المعاملات و الرموز التي قد تتواجد داخل برنامج مكتوب بالـ ++C و هي:

preprocessing-op-or-punc: one of	{   }   [   ]   #   ##   (   )	<:   :>   <%   %>   %:   %:%:   ;   :   ...	new   delete   ?   ::   .   .*	+   -   *   /   %   ˆ   &   |   ˜	!   =   <   >   +=   -=   *=   /=   %=	ˆ=   &=   |=   <<   >>   >>=   <<=   ==   !=	<=   >=   &&   ||   ++   --   ,   ->*   ->	and   and_eq   bitand   bitor   compl   not   not_eq	or   or_eq   xor   xor_eq

بعض المعاملات توجد لها صيغ بديلة[12] و هي:

┌───────────────────────────────┬───────────────────────────────┐│   primary       alternative   │   primary       alternative   │├───────────────────────────────┼───────────────────────────────┤│     {               <%        │      |             bitor      │├───────────────────────────────┼───────────────────────────────┤│     }               %>        │      ^              xor       │├───────────────────────────────┼───────────────────────────────┤│     [               <:        │      ~             compl      │├───────────────────────────────┼───────────────────────────────┤│     ]               :>        │      !              not       │├───────────────────────────────┼───────────────────────────────┤│     #               %:        │      &=            and_eq     │├───────────────────────────────┼───────────────────────────────┤│     ##              %:%:      │      |=             or_eq     │├───────────────────────────────┼───────────────────────────────┤│     &&              and       │      ^=            xor_eq     │├───────────────────────────────┼───────────────────────────────┤│     ||               or       │      !=            not_eq     │├───────────────────────────────┼───────────────────────────────┤│     &              bitand     │                               │└───────────────────────────────┴───────────────────────────────┘

داخل البرنامج يعطي استخدام الصيغة الأساسية أو البديلة للمعامل نفس المعنى[13].




وحدات أخرى

أي حرف غير المساحة البيضاء لا يتم مطابقته مع صيغ المعالج التي تم ذكرها يسبب خطأً و يجعل المعالج يتوقف.





وحدات الترجمة

بعد أن ينتهى المعالج من عمله يكون قد كوّن قائمةً بمجموعة من الوحدات اللتي تم تحويلها إلى وحدات اللغة[14] Compiler Tokens.

وحدات اللغة تشبه وحدات المعالج و لكنها موجهة للمترجم و هي:

  • معرف identifier.
  • كلمة محجوزه keyword.
  • قيمه ثابتة literal.
  • معاملات operator.
  • فواصل punctuator.

القيم الثابته literals تنقسم لعدة اقسام:

┌───────────────────┐│ integer-literal   │├───────────────────┤│ floating-literal  │├───────────────────┤│ boolean-literal   │├───────────────────┤│ character-literal │├───────────────────┤│ string-literal    │└───────────────────┘

الـ character-literal و string-literal لا يتم تغييرها لأي وحدات أخرى.

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

┌───────────────────┬──────────────────┐│ prepro token      │  compiler token  │├───────────────────┼──────────────────┤│  comments         │  white-space     │├───────────────────┼──────────────────┤│  header-name      │  --deleted--     │├───────────────────┼──────────────────┤│  identifier       │  identifier      ││                   │  keyword         │├───────────────────┼──────────────────┤│  pp-number        │  literal         │├───────────────────┼──────────────────┤│  char-literal     │  literal         │├───────────────────┼──────────────────┤│  string-literal   │  literal         │├───────────────────┼──────────────────┤│  op-or-punc       │  operator        ││                   │  punctuator      │└───────────────────┴──────────────────┘

الجدول السابق يحدد:

  • الملاحظات يراها المترجم كأنها مساحات فارغة.
  • الـ header-name تم حذفها من قبل المعالج.
  • الـ preprocessing-op-or-punc تم تقسيمها إلى operators و هي عائلة معاملات الـ assignment و المعاملات الرياضية و المعاملات المنطقية و معاملات البت و scope-resolution، و الـ punctuators هي باقي المعاملات.
  • الـ character-literal و string-literal مع العلم انهما لم يتغيرا إلا أنه تم إضافة وصف جديد لهم وهو literal.
  • الـ pp-number يتم تحويلها لـ literal و يتم تحديد أنها إما integer-literal أو floating-literal.
  • الـ identifier يتم استخلاص الـ keywords منه و الباقي يبقى كما هو.
  • الـ keywords المستخدمة يتم تحديد بعضها بأنه boolean-literal.

الـ literal هي قيم لا يتم تغييرها سواء وقت الترجمة أو وقت التشغيل[15]، و يمكنك اعتبارها وصفاً عامّاً يندرج تحته عدة أنواع من القيم.




القيم الصحيحه integer-literals

مشروح فى 2.13.1، القيم الصحيحة تأخذ الصيغة التالية:

integer-literal:	decimal-literal integer-suffix[opt]	octal-literal integer-suffix[opt]	hexadecimal-literal integer-suffix[opt]decimal-literal:	nonzero-digit	decimal-literal digitoctal-literal:	0	octal-literal octal-digithexadecimal-literal:	0x hexadecimal-digit	0X hexadecimal-digit	hexadecimal-literal hexadecimal-digitnonzero-digit: one of	1 2 3 4 5 6 7 8 9octal-digit: one of	0 1 2 3 4 5 6 7hexadecimal-digit: one of	0 1 2 3 4 5 6 7 8 9	a b c d e f	A B C D E Finteger-suffix:	unsigned-suffix long-suffix[opt]	long-suffix unsigned-suffix[opt]unsigned-suffix: one of	u Ulong-suffix: one of	l L

القيمة الرقمية الصحيحة:

  • هي سلسلة من الأعداد لا تحتوى على الفاصلة عشرية أو الأس.
  • قد تحتوي على سابقة تحدد الأساس المستخدم، و قد تحتوي على لاحقة لتحدد النوع الصحيح الذي يتم تمثيل الرقم به.
  • أول رقم في السلسلة (من جهة اليسار) هو الـ most-significant.
  • السلسلة ذات الأساس 10 (نظام العد العشري) تبدأ بأي رقم غير الصفر و تتكون من الأعداد فى المدى من 0 إلى 9.
  • السلسلة ذات الأساس 8 (نظام العد الثماني) تبدأ بالرقم صفر و تتكون من الأعداد فى المدى من 0 إلى 7.
  • السلسلة ذات الأساس 16 (نظام العد السداسي عشر) تبدأ بـ 0x أو 0X و تتكون من الأعداد فى المدى من 0 إلى 9 و الحروف في المدى من a إلى f و الحروف في المدى من A إلى F. هذه الحروف تمثل الأرقام من 10 إلى 15 في النظام العشري.

مثال: الرقم 27 يتم تمثيله في الأنظمة بالشكل التالي:

  • الأساس 10: 27.
  • الأساس 8: 033.
  • الأساس 16: 0x1B أو 0X1B او 0x1b او 0X1b.

تحديد نوع القيمة الرقمية الصحيحة[16] قائم على ثلاثة عوامل و هي كيفية كتابته و قيمته و اللاحقة حيث:

  • إذا كانت السلسلة للأساس 10 و بدون لاحقة فنوعها هو أول نوع من الأنواع التالية يمكن حفظ قيمة السلسلة به: int -> long int. إذا كانت القيمة لا يمكن حفظها فى long int فهذا ينتج undefined behavior.
  • إذا كانت السلسلة للأساس 8 أو الأساس 16 و بدون لاحقة فنوعها هو أول نوع من الأنواع التالية يمكن حفظ قيمة السلسلة به: int -> unsigned int -> long int -> unsigned long int.
  • إذا كانت السلسلة تنتهي باللاحقه u أو U فنوعها هو أول نوع من الأنواع التالية يمكن حفظ قيمة السلسلة به: unsigned int -> unsigned long int.
  • إذا كانت السلسلة تنتهي باللاحقة l او L فنوعها هو أول نوع من الانواع التالية يمكن حفظ قيمة السلسلة به: long int -> unsigned long int.
  • إذا كانت السلسلة تنتهي بأي من اللواحق ul, lu, uL, Lu, Ul, lU, UL, LU فنوع القيمة هو unsigned long int.

الـ translation unit تعتبر ill-formed إذا كانت تحتوي على سلسلة رقمية و ذات قيمة لا يمكن حفظها بأي من الأنواع المذكورة.




القيم العشرية float-point literals

مشروح فى 2.13.3، القيم العشرية تأخذ الصيغة التالية:

floating-literal:	fractional-constant exponent-part[opt] floating-suffix[opt]	digit-sequence exponent-part floating-suffix[opt]fractional-constant:	digit-sequence[opt] . digit-sequence	digit-sequence .exponent-part:	e sign[opt] digit-sequence	E sign[opt] digit-sequencesign: one of	+ -digit-sequence:	digit	digit-sequence digitdigit: one of	0 1 2 3 4 5 6 7 8 9floating-suffix: one of	f l F L

القيمة العشرية:

  • يتم تمثيلها باستخدام الصيغة العلمية على الهيئة A.B x 10p داخل الأساس 10.
  • تتكون من رقم صحيح (A) ثم العلامة العشرية (.) ثم قيمة الكسر ( B ) ثم الحرف e أو E (و هو اختياري) - و تحدد وجود الأس - ثم قيمة الأس (p) و قد تحتوي على إشارة سالبة أو موجبة وعدم وجودها يعني الإشارة الموجبة و في النهاية لاحقة اختيارية لتحدد نوع القيمة العشرية.
  • يمكن كتابتها باستخدام الرقم الصحيح فقط أو القيمة الكسرية فقط أو كليهما معاً.
  • يمكنك ستخدام الفاصلة العشرية فقط أو eE مع الأس أو كليهما معاً.

خصائص القيمة العشرية:

  • الرقم الصحيح و العلامه العشرية و قيمة الكسر معاً تمثل القيمة العشرية، و إذا وُجد الأس فإنه يمثل قيمة الإزاحة التي ستتم على القيمة العشرية.
  • عدم وجود لاحقة تعني أن نوع القيمة double و اللاحقة f أو F تعني أن نوع القيمة float و اللاحقة l أو L تعني أن نوع القيمة long double.
  • إذا كانت القيمة العشرية بعد الإزاحة لا يمكن حفظها داخل النوع المحدد فإنه يتم الحصول على أقرب قيمة للقيمة العشرية بعد الإزاحة ليتم حفظها في ذلك النوع، القيمة الجديدة هي implementation-defined.
  • إذا كانت القيمة العشرية بعد الإزاحة خارج المدى المحدد لنوعها فالبرنامج يعتبر ill-formed.




القيم المنطقية boolean-literal

مشروحه فى 2.13.5، تأخذ الصيغة التالية:

boolean-literal:	false	true

القيم المنطقية يتم تمثيلها بالكلمتين المحجوزتين true و false و لهما النوع bool.




[1] هذا الموضوع يحتاج قراءة مسبقة لكل مواضيع السلسلة التى تسبقه.
[2] راجع النقطة الثانية في موضوع مفاهيم أساسية، الجزء الثاني.
[3] في مراحل الترجمة تم إعطاء شرح مجمل و مفصل للعديد من النقاط و في هذا الجزء من الموضوع سنقوم بتفصيل النقاط المجملة و سنركز على النقطة 3.2 جيدا.
[4] داخل توثيق اللغة هذه القيود تتواجد في أكثر من مكان و بأكثر من صيغة و أحياناً تجد بعضها أعم من آخر، لهذا و حتى لا أعيد كتابة توثيق اللغة قمت بوضع الحالة العامة و وضعت الموقع الذي يوجد فيه التخصيص و التعميم.
[5] حتى لحظة كتابة هذا الموضوع فإن معايير ISO 10646 مماثلة لـ UTF-16 من Unicode.
[6] الـ underscore هي الرمز الذى رقمه 0x005F و يأخذ فى الأغلب الشكل "_".
[7] مجال الأسماء العام هو مجال الأسماء الرئيسي الذي يوضع داخل كافة عناصر البرنامج و لا اسم له، فمثلاً إذا كتبت برنامجك بدون وضعه داخل أي مجال أسماء فبرنامجك مكتوب داخل مجال الأسماء العام.
[8] الأرقام التى تستخدم مع if# لها النوع size_t و سيتم شرحه مع أوامر المعالج.
[9] الأنواع الأساسية سيتم شرحها بالتفصيل لاحقا
[10] المصطلح الصحيح هو static storage duration و هذا المصطلح مرتبط بالـ storage classes و التي سيتم شرحها لاحقاً مع البقية منها.
[11] الترميز الذي يقوم بوصف حرف واحد داخل أكثر من byte يسمى بـ multibyte encoding و مثال عليه UTF8 أو UTF16 من Unicode.
[12] الصيغ البديلة مذكورة فى 2.5.2
[13] سبب الصيغ البديلة هو نفسه سبب وجود الـ trigraph sequences وهو وجود code pages لا تدعم بعض الرموز و حينها الصيغ البديلة ستفي بالغرض.
[14] تم ذكرها فى 2.6.
[15] القيمه الثابته literal تختلف عن الثابت constant فى أن الثابت يحتوي إما على موقع القيمة أو نسخة منها و بالتالي يمكنك تغيير قيمة الثابت وقت تشغيل البرنامج - باستخدام const_cast - و لكن دائما و ابداً لا يمكنك تغيير القيمة التي استخدمت وقت الترجمة و التي تم كتابتها داخل الكود.
[16] الإصدار C++2003 لا يحتوى على النوعين long long int و unsigned long long int و استخدامهما داخل برنامجك يجعله غير موافق لمواصفات C++2003 القياسية.

4

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .