لماذا يوجد عدد قليل جدًا من المترجمين الفوريين لـ C++؟


أنا شخصيًا أعرف مترجمًا واحدًا فقط لـ C++، والذي يستخدمه Root (CINT، الذي تم تطويره في CERN). لقد جعلني أتساءل لماذا يوجد عدد قليل جدًا، والإجابة الواضحة هي أن لغة C++ هي لغة معقدة جدًا للتحليل. لن يزعج أي شخص بكامل قواه العقلية كتابة محلل لغة C++ من الصفر…

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

ومع ذلك، يبدو أنه لم يقم أحد بذلك، وهو ما يعني عادة أن الأمر ليس سهلاً كما يبدو (لا يعني ذلك أن فكرتي ستكون تافهة، لكنها لا تزال). كنت أتساءل ما هي المشاكل التي ستواجه فكرتي… هل هناك من يهتم بالتعليق؟

الحل 1

يرجى الاطلاع على التعليقات على السؤال، من خلال bling (فكرة جيدة حول C++/CLI)، وأنا.

الحقيقة هي: CINT ليس مترجمًا لـ C++. CINT ليس مترجمًا لـ C++. وهذا ما ورد بوضوح هنا:

[^].

اللغة هي لغة مبسطة تعتمد على C وC++.

أنظر أيضا: http://root.cern.ch/drupal/content/cling[^].

ماذا عن بديل واحد مذكور في مقالة ويكيبيديا المشار إليها أعلاه، “Ch”؟ هذا ليس مترجم C++ بالضبط، إنه مترجم لبعض اللغات الخاصة:
http://en.wikipedia.org/wiki/Ch_%28computer_programming%29[^],

[^].

أي شيء آخر؟ “Pike”، يعتمد أيضًا فقط على C وC++ (حتى أن ويكيبيديا تقول “متأثر بـ”):
http://en.wikipedia.org/wiki/Pike_%28programming_language%29[^],

[^].

أما بالنسبة للغة C++ “الحقيقية”، فأعتقد أن البعض يعتقد أنها غير مناسبة لمترجم فوري؛ الموضوع معقد للغاية بحيث لا يمكن مناقشة اعتباراتي في ملف سريع أسئلة و أجوبة. لا أستطيع إثبات ذلك هنا ولست متأكدًا بنسبة 100%، لأنني أميل إلى الاعتقاد أنه من الممكن إثباته. سأكون مندهشًا جدًا إذا أثبت شخص ما أنني مخطئ.

-سا

الحل 3

يقتبس:

أنا شخصيًا أعرف مترجمًا واحدًا فقط لـ C++، والذي يستخدمه Root (CINT، الذي تم تطويره في CERN). لقد جعلني أتساءل لماذا يوجد عدد قليل جدًا، والإجابة الواضحة هي أن لغة C++ هي لغة معقدة جدًا للتحليل. لن يزعج أي شخص بكامل قواه العقلية كتابة محلل لغة C++ من الصفر…

هناك بعض الأسئلة المهمة هنا: ما هو هدفك ولماذا يكون مترجم C/C++ هو الحل الأفضل (أو على الأقل جيد بشكل معقول) لهذه المشكلة؟ “ما هو هدفك؟” و”لماذا يعتبر X حلاً جيدًا؟” هي عمومًا أسئلة أولية جيدة جدًا يجب طرحها قبل إضاعة الوقت الثمين في تنفيذ الحل.

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

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

يتطلب C/C++ إعلانات إلى الأمام. في اللغة المفسرة العملية لا توجد إعلانات أمامية ولا توجد إعلانات/تعريفات منفصلة. ولكن هذا مجرد جزء صغير من مشكلة أكثر خطورة: لغة C/C++ مطولة بشكل غير عملي لاستخدامها كلغة مترجمة. هذه مجموعة من المشكلات التي تتضمن مشكلات تصميم اللغة ومشاكل قابلية الاستخدام العملية كلغة مفسرة. في لغة بايثون، يمكنني بسهولة تحديد دالة X تستدعي دالة Y غير موجودة ويُسمح لي بتعريف وظيفة Y هذه لاحقًا. ثم يمكنني تنفيذ X. لاحقًا، إذا أردت، يمكنني تغيير تعريف Y تمامًا (ربما مع بعض المعلمات الجديدة التي تمت تهيئتها افتراضيًا لتكون متوافقة مع التعريف السابق) ويستخدم تنفيذ آخر لـ X على الفور تعريف Y الجديد. يمكنني تنفيذ X حتى لو كانت تستدعي دالة Z لم يتم تعريفها بعد، وهذه ليست مشكلة إذا كان تنفيذ X باستخدام معلمات الإدخال الفعلية لا يعمل فعليًا في الفرع الذي قد يستدعي Z. مترجم C++ ماذا يحدث إذا قمت بتغيير تعريف القالب الأساسي جدًا (على سبيل المثال: المصفوفة الديناميكية) الذي يستخدمه الكثير من الوظائف المحددة مسبقًا (على سبيل المثال كوظائف مضمنة)؟ كيف يمكنك معرفة كتل التعليمات البرمجية التي تحتاج إلى إعادة الترجمة داخل المترجم الفوري الخاص بك من أجل استخدام الوظائف المضمنة الجديدة؟ ماذا يحدث إذا فشلت إعادة ترجمة بعض هذه الوظائف مع التعريف الجديد؟ ليس لديك مشاكل خطيرة كهذه مع اللغات الديناميكية مثل بايثون. قد يكون التعامل مع مثل هذه السيناريوهات في مترجم غير ديناميكي مشكلة كبيرة، وكانت هاتان المشكلتان “بسيطتان/أساسيتان” فقط، وهذه مجرد قمة جبل الجليد. لقد قمت ببرمجة C/C++ لأكثر من عقد من الزمن ولم أشعر أبدًا بالحاجة إلى مترجم C/C++.

يقتبس:

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

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

يجب عليك الإجابة على الأسئلة التي نشرتها في الفقرة السابقة. من سؤالك أعتقد أن هدفك ربما يكون الإبداع ببساطة أ مترجم C++ مع أقل قدر من العمل المستثمر – أفترض ذلك لأنك تريد إعادة استخدام الأشياء (وحدات الترجمة، ملفات الكائنات) من المترجمين الحاليين. مشكلتي في هذا هي أن الناس يفعلون شيئًا “بأقل جهد مستثمر” عندما يتعين عليهم القيام بشيء لا يحبونه. من ناحية أخرى، إذا كانوا يفعلون شيئًا ما من أجل المتعة فقط كهواية أو لغرض محدد، فعادةً لا يمانعون في القيام بالكثير من العمل. في حالة وجود مترجم C/C++، يبدو أن جميع الحلول تتطلب الكثير من العمل.

اعتمادا على المترجم وإعدادات المترجم، قد تحتوي ملفات الكائنات على شيء آخر غير ما تحتاجه. إنها ليست موحدة وحتى نفس المترجم يمكنه وضع القمامة عديمة الفائدة تمامًا فيها باستخدام بعض الإعدادات (مثل LTCG). IMO سيكون من العملي أكثر كتابة واجهة خلفية لإصدار ما تحتاجه بدلاً من محاولة تحليله من ملفات الكائنات.

الحل 4

سبب تخميني: يبدو أنه لا يوجد أحد لديه الحاجة مقارنة بالجهد المبذول للقيام بذلك. أي أنك قد تكون قادرًا على بناء برج إيفل في حديقتك، على افتراض أن لديك المساحة، والمواد، والأشخاص، والأرض الجيدة بما يكفي، وما إلى ذلك، ويمكنك القيام بذلك من أجل متعتك الخاصة. ؛-)

الفرق من C إلى C++ هو كما هو مذكور في معيار C++:

بالإضافة إلى التسهيلات التي توفرها لغة C، توفر لغة C++ أنواع بيانات إضافية، وفئات، وقوالب، واستثناءات، ومساحات الأسماء، والتحميل الزائد للمشغل، والتحميل الزائد لاسم الوظيفة، والمراجع، ومشغلي إدارة المتجر المجاني، ومرافق المكتبة الإضافية.

إذا ذهبت إلى C++ 11، فيمكنك إضافة تعبيرات لامدا والعديد من الأجزاء الأخرى، وكلها بشكل أساسي عبارة عن سكر نحوي بمعنى أنها تلخص شيئًا يتعلق بشكل أساسي بالمحلل ويمكن القيام به أيضًا (إن لم يكن مملاً) بوسائل أخرى.

ما هي النتائج كعناصر وقت التشغيل من تحليل الميزات المذكورة أعلاه
– أنواع بيانات إضافية: بعض أنواع الأحرف/الأرقام المضمنة
– الفئة: وظائف المثيل الموسعة مع this معامل
– الفئة: الميراث مع الفئة الأساسية ككائن فرعي لفئة مشتقة
– الفئة: استدعاءات الوظائف الضمنية الخاصة (ctor، dtor، إلخ.)
– الفئة: vtable لاستدعاءات الوظائف الافتراضية
– الفئة: ترتيب التعريفات (في الغالب) لا يهم في الفئات – يتأثر البحث عن الاسم فقط
– القوالب: فئات أو وظائف تم إنشاؤها بناءً على النوع أو القيم المتكاملة الثابتة
– الاستثناءات: تدفق التحكم الإضافي وخاصة كود التنظيف ومسك الدفاتر
– مساحات الأسماء: “السكر النحوي” (يتم تعريف واستدعاء الأنواع والكائنات والوظائف الفريدة)
– التحميل الزائد: “السكر النحوي” (يقوم المحلل اللغوي بإنشاء استدعاءات للوظائف الصحيحة)
– المراجع: “السكر النحوي”، ينتج عنه مؤشرات أو لا يوجد كود وقت تشغيل على الإطلاق
– جديد/حذف: ذاكرة منخفضة المستوى malloc/مجانية بالإضافة إلى مكالمات ctor/dtor
– المكتبات: مجموعة من العناصر التي تعتمد على ميزات اللغة
– تعبير لامدا: “السكر النحوي” (فئة المؤثر الضمني)
– …

هناك مشاكل تفصيلية سيئة يجب التغلب عليها، ولكن من الناحية الفنية يمكن اعتبارها لغة C ممتدة كثيرًا.

لذلك، إذا كان لديك واجهة أمامية لـ C++ تمكنت من الترجمة إلى لغة C مكافئة وظيفيًا، فقد وصلت إلى مستوى CINT. مشاكل مثل الملفات المتعددة والمكتبات المرجعية وملفات الكائنات ليست فريدة بالنسبة لـ C++ ولكنها حقيقة شائعة مع جميع لغات C*. لذلك، يمكنك إعادة استخدام هذه المفاهيم الخاصة بمترجم تلك اللغات (CINT؟).

ولكن مرة أخرى، يعتمد تبرير الجهود إلى حد كبير على “المكاسب” المتوقعة.

هتافات
و انا

الحل 5

لأن C++ هي لغة برمجة ضخمة. إنها معقدة للغاية. يتم إنشاء المترجمين الفوريين للغات مثل Python وJavaScript، ليس فقط لأنها بسيطة، ولكن من المفترض أن يتم تفسيرها، فهي ديناميكية. أول تطبيق لبايثون كان عبارة عن مترجم؛ ليس مترجم. ليس هذا هو السبب فحسب. من المعروف بالفعل أن لغة C++ أسرع من اللغات المترجمة عند “الترجمة”. ولكن لا يمكنك دائمًا توقع نفس الشيء من مترجم C++. لغة C++ حساسة للسياق؛ لغة C++ ضخمة؛ يحتوي C++ على الأدوية العامة. وبالتالي، فإن تعقيد اللغة يساهم في المعالجة البطيئة للكود المصدري. على سبيل المثال، راجع سرعات الترجمة لـ C++. ماذا سيحدث إذا قمت بتفسير المصدر؟ ومع ذلك، فإن برنامج “hello World” الكلاسيكي قد لا يستغرق بعض الوقت. لكن هل تفكر في برنامج يستخدم التقنيات العامة بكثرة؟

ولكن لا يزال هناك بعض المترجمين الفوريين مثل CINT، Ch. انظر الصفحة التالية:

[^]

الحل 2

من الصعب حقًا “حل” هذا السؤال – ربما كان الأمر أفضل في المنتدى، ولكن إليك 2C.

تعريف اللغة لا يمنع حقًا إنشاء مترجم، ولكن تم تصميم C++ بالفعل كلغة منخفضة المستوى يمكن استخدامها لتعليمات برمجية فعالة للغاية. اللغة معقدة للغاية، ولكن ليس من المستحيل تحليلها (AFAIK يتطلب حقًا محلل GLR أو محلل مكتوب بخط اليد). ومع ذلك، فإن معظم فوائد C++ تأتي من حقيقة أنه يمكن استخدامها في التعليمات البرمجية الفعالة، التي تعمل بالقرب من الجهاز. يُستخدم المترجمون عادةً في المهام عالية المستوى، حيث يكون التكرار السريع أثناء التطوير أكثر أهمية من سرعة التنفيذ.

باختصار، سيكون الأمر بمثابة جحيم للكثير من العمل، وسوف يركض مثل الكلب.

コメント

タイトルとURLをコピーしました