Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

المحلل المعجمي (Lexer)

ماذا ستتعلّم: كيف يحوّل LexerCore نصّ (UTF-8) إلى تيار Token، بتفصيل دقيق من الكود الفعليّ — بما فيه المعالجة الذكيّة للمحارف العربية متعدّدة البايتات.

📎 المصدر: shared/lexer/src/lexer_core.cpp · token.h · lexer_keywords.cpp

البناء والنظر المسبق

LexerCore(source) يحتفظ بالمصدر ومؤشّر current_ وموقع Position. الأدوات الأساسيّة:

Position يبدأ من 1 (سطر/عمود) وoffset من 0.

موزِّع nextToken() — ترتيب الإرسال

الدالة المحوريّة nextToken() تتبع ترتيبًا حسّاسًا (الترتيب يمنع لبس المحارف العربية):

flowchart TD
  N["nextToken()"] --> WS["حلقة: skipWhitespace + التعليقات (# #* ## #**)"]
  WS --> EOF{"نهاية الملف؟"}
  EOF -- نعم --> E["END_OF_FILE"]
  EOF -- لا --> D{"تصنيف المحرف"}
  D -->|رقم عربيّ/إنجليزيّ| NUM["scanNumber()"]
  D -->|'r\"' أو 'ح\"'| RAW["scanRawString()"]
  D -->|'f\"' أو 'م\"' أو 'ص\"'| FS["scanFString()"]
  D -->|'\"'| STR["scanString()"]
  D -->|'×' (0xC3 0x97)| MUL["OP_MULTIPLY"]
  D -->|'،' '؛' '؟' (0xD8 ..)| ARB["ARABIC_COMMA / SEMICOLON / QUESTION"]
  D -->|حرف/‎_‎/عربيّ| ID["scanIdentifier()"]
  D -->|عامل| OP["scanOperator()"]

⭐ المعالجة الدقيقة لـUTF-8 (نقطة متقدّمة)

المحارف العربية متعدّدة البايتات تُفحَص قبل scanIdentifier وإلّا ابتلعها كجزء من مُعرّف:

المحرفUTF-8الرمز الناتجالموقع
رقم عربيّ ٠–٩0xD9 + 0xA0..0xA9عدد → scanNumberL1646
ح" (نصّ خام)0xD8 0xAD + "STRING_RAWL1675
م" / ص" (نصّ منسَّق)0xD9 0x85 / 0xD8 0xB5 + "STRING_FSTRINGL1694
× ضرب0xC3 0x97OP_MULTIPLYL1726
، فاصلة0xD8 0x8CARABIC_COMMAL1743
؛ منقوطة0xD8 0x9BARABIC_SEMICOLONL1753
؟ استفهام0xD8 0x9FQUESTION؟.QUESTION_DOT)L1760

💡 لهذا تعمل س، ص وأ ؟ ب : ج و٣ × ٤ كما لو كُتبت باللاتينيّة — المعجمي يطبّع المحارف العربية إلى رموز قياسيّة.

الماسحات (Scanners)

الدالةالموقعيمسح
scanNumberL323صحيح/عشريّ + 0x/0b/0o؛ يترك .. لماسح العوامل (المدى)
scanStringL754"..." مع هروب \n \t \\ \" \r \b \f \v \0 \u \U \x
scanRawStringL998r"..."/ح"..." بلا معالجة هروب
scanFStringL1054f"...{تعبير}..."
scanDocCommentL1167## / #** **# (يُرفَق بأوّل تصريح)
scanIdentifierL1250مُعرّف UTF-8 (يتوقّف قبل ،/؛)
scanOperatorL1347العوامل (switch على `+ - * / % = < > ! . ^

التعليقات

حلقة التخطّي في بداية nextToken تعالج: # سطر · #* … *# كتلة · ## توثيق سطر · #** … **# توثيق كتلة (التعليق غير المغلق يرمي خطأً). تعليقات ## تُلتقَط وتُرفَق لاحقًا بأوّل تصريح (انظر تهيئة المحلل النحوي).

الكلمات والرموز

  • محجوزة (40): مسجّلة في lexer_keywords.cpp (KeywordTable::initialize())، مصدرها language-truth/keywords.yaml.
  • سياقيّة: لها KEYWORD_* في token.h لكنها لا تُسجَّل كمحجوزة؛ يميّزها المحلل النحوي بالسياق.
  • أنواع مدمجة كمُعرّفات: رقم/نص/… ليست محجوزة.

إضافة كلمة مفتاحيّة (مختصر)

  1. أضف KEYWORD_FOO إلى token.h. 2. محجوزة: سجّلها في keywords.yaml ثم أعد توليد keywords_generated. سياقيّة: لا تسجّلها، واستخدم التحقّق المزدوج في المحلل النحوي.
  2. أضف القاعدة + عقدة AST + الزوّار + codegen + اختبار. → التشابك.

اقرأ بعده: المحلل النحوي.