Skip to content

اشتقاقُ التنزيلِ من التنفيذِ لا من الحدس

١ · السؤالُ الذي لم يكن له جواب

مصدرُ الحقيقةِ يعلنُ ١٠٧ قاعدةَ نحو. والخلفيّةُ الأصليّةُ (بلا LLVM) تخفضُ مجموعةً من أوپكودات SIR. وبينهما فجوةٌ تجعلُ سؤالًا بسيطًا غيرَ قابلٍ للقياس: «أتدعمُ الخلفيّةُ الأصليّةُ قاعدةَ لكل؟»

الجوابُ الشائعُ أن يكتبَ مهندسٌ جدولًا: قاعدةٌ ← أوپكودات. وهذا الجدولُ يبلى في أوّلِ رقعةٍ تُغيِّرُ الخفض، ولا شيءَ يكشفُ بلاه: هو نثرٌ يوافقُ نفسَه دائمًا.

٢ · المنهج: يُترجَمُ، ثمّ يُقرَأُ ما خرج

scripts/codegen/gen_grammar_lowers_to.py يشتقُّ الجدولَ بالتشغيل:

  1. خطُّ الأساس: يُترجَمُ برنامجٌ أدنى (دالّةٌ فارغة) بـ--أظهر-sir، فتُجمَعُ أوپكوداتُ السقالةِ التي يبثُّها المولِّدُ لأيِّ دالّةٍ كانت. المُودَعُ اليوم: baseline_opcodes أربعةَ عشرَ أوپكودًا.
  2. لكلِّ قاعدة: تُترجَمُ عيّنةٌ من بذورِها في rules_matrix بالعَلَمِ نفسِه (samples_per_rule: 3)، وتُجمَعُ أوپكوداتُها.
  3. lowers_to = اتّحادُ أوپكوداتِ القاعدةِ كاملًا — سقالةً ومضمونًا — لأنّ الحكمَ على الخلفيّةِ يلزمُه كلُّ ما يحتاجُه البرنامجُ فعلًا. وbeyond_baseline هو ما تُضيفُه القاعدةُ فوقَ السقالة.
  4. ما لم يُترجَمْ لا يُدَّعى: القاعدةُ بلا بذرةٍ ناجحةِ الترجمةِ تُوسَمُ status: not_derived صراحةً، ولا تُترَكُ خانتُها فارغةً موحيةً بالنجاح.
bash
python scripts/codegen/gen_grammar_lowers_to.py   --compiler build/bin/Release/sad-build.exe --recompute

٣ · مثالٌ يُرى بالعين: توقف لا أوپكودَ لها

بذرةُ gr.stmt.break/basic/001_in_while.ص كما هي في الشجرة، ثمّ SIR الذي يخرجُ عنها:

bash
sad-build.exe 001_in_while.ص --أظهر-sir -o out.exe
define void @__sad_main() {
entry:
    %%ع = alloc
    store 0, %%ع
    br label %while_cond_0
while_cond_0:
    %%2 = lt %%ع, 10
    br.cond %%2, label %while_body_1, label %while_exit_2
while_body_1:
    %%4 = eq %%ع, 2
    br.cond %%4, label %while_exit_2, label %merge_4
while_exit_2:
    ret.void
merge_4:
    builtin.print %%ع
    ...
}

لا أوپكودَ اسمُه BREAK. توقف صارت br.cond تقفزُ إلى while_exit_2 مباشرةً. جدولٌ مكتوبٌ باليدِ كان سيخترعُ خانةً باسمِ القاعدة؛ والاشتقاقُ بالتنفيذِ يقولُ الحقيقة: القاعدةُ تُنزَّلُ إلى فروعٍ لا إلى تعليمةٍ خاصّةٍ بها.

والمدخلُ المُودَعُ في language-truth/grammar/lowers_to.yaml:

yaml
- id: gr.stmt.break
  status: derived
  lowers_to: [ADD_I64, ALLOC, ARRAY_GET, ARRAY_LEN, ARRAY_NEW, ARRAY_SET,
              BR, BR_COND, BUILTIN_PRINT, EQ, LOAD, LT, MOVE, RET_VOID, STORE]
  beyond_baseline: [ADD_I64, ARRAY_SET, BUILTIN_PRINT, EQ, LT, MOVE, RET_VOID]
  native_ok: [arm64, x86_64]
  native_missing_riscv64: [ADD_I64, ARRAY_GET, ARRAY_LEN, ...]
  evidence: [001_in_while.ص, 002_in_for.ص, 003_first_iter.ص]

٤ · حقلُ evidence هو الفرق

الصفُّ يحملُ أسماءَ البذورِ التي اشتُقَّ منها. فالدعوى قابلةٌ للتكذيب بخطوةٍ واحدة: افتحِ البذرةَ المسمّاة، ترجِمْها بـ--أظهر-sir، وقابِلْ. جدولٌ بلا شواهدَ لا يمكنُ تكذيبُه لأنّه لا يقولُ من أين جاء.

٥ · الأرقام، وكيف تُعاد

bash
python scripts/codegen/check_lowers_to.py
① الكتالوج: 780 أوپكودًا (الطزاجة: محدَّث) · مخفوضٌ أصليًّا: 104
② التغطية: 107/107 قاعدةً لها مدخل · مُشتقّة 105 · غير مقيسة 2
③ المفردات: كلُّ أوپكودٍ مذكورٍ في lowers_to معروفٌ في الكتالوج
④ الانجراف: 2 دَينًا مُعلَنًا (يُطبَع ولا يُفشِل)
   ⚠️ arm64/isel.yaml يذكر أوپكودًا غير موجودٍ في تعداد المترجم: CONST_I64
   ⚠️ x86_64/isel.yaml يذكر أوپكودًا غير موجودٍ في تعداد المترجم: CONST_I64

▸ دعم الخلفيّة الأصليّة (بلا LLVM) — من المُشتقّ فقط:
   arm64      102/105 قاعدة مُشتقّة (102/107 من الكلّ)
   riscv64    26/105 قاعدة مُشتقّة (26/107 من الكلّ)
   x86_64     102/105 قاعدة مُشتقّة (102/107 من الكلّ)

القاعدتانِ غيرُ المشتقّتَين: gr.adv.property_test وgr.adv.ffi_ctype. 🔑 وهما بعينِهما القاعدتانِ الوحيدتانِ بلا مرساةٍ في الشجرةالمطابقة). لا مصادفةَ في ذلك: الاشتقاقُ يقرأُ بذورَ القاعدة، فقاعدةٌ بلا بذرةٍ قاعدةٌ بلا تنزيلٍ مشتقّ. عطبٌ واحدٌ يظهرُ في عدّادَينِ مستقلَّين — وهذه علامةُ أنّ العدّادَينِ يقيسانِ الواقعَ لا بعضَهما.

٦ · حدودٌ مقيسة

  • samples_per_rule: 3. المدخلُ حدٌّ أدنى لمجموعةِ الأوپكودات لا انغلاقُها: صياغةٌ من القاعدةِ لم تُؤخَذْ في العيّنةِ قد تبثُّ أوپكودًا خارجَ القائمة. فـ«مدعومةٌ أصليًّا» تعني «مدعومةٌ على ما قِيس».
  • الحكمُ على الخلفيّةِ يشملُ السقالة. lowers_to لا يطرحُ خطَّ الأساس، لأنّ طرحَه يُخفي أنّ السقالةَ نفسَها قد لا تُخفَض. ولهذا gr.stmt.break تحملُ ARRAY_NEW وليست في نصِّ القاعدة: عيّنتُها فيها حلقةُ لكل على مصفوفة.
  • دَينُ انجرافٍ مُعلَنٌ لا يُفشِل: CONST_I64 مذكورٌ في جدولَي isel لمعماريّتَين وليس في تعدادِ أوپكوداتِ المترجّم. يُطبَعُ في كلِّ تشغيلة، ولا يُوقِفُ الدمجَ — دَينٌ مُقيَّدٌ لا سكوتٌ عنه.
  • الاشتقاقُ الكاملُ ليس في البوّابة؛ هو يدويٌّ بـ--recompute لأنّه يعيدُ ترجمةَ مئاتِ البذور. المُشغَّلُ في x.py gen --check هو الفحصُ الرخيص: كتالوجٌ بائت، قاعدةٌ بلا مدخل، ومعماريّةٌ تدّعي lowered بلا خفض.

مُرخَّص بموجب رخصة MIT