تحويل الإدخال إلى رموز
حوّل النص إلى رموز
تحويل الإدخال إلى رموز درس مجاني في C Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C Academy 4 دروس في المجموع.
ما هو المحلّل الرمزي؟
يبدأ المفسّر بتحويل النص الخام إلى رموز — وهي أصغر الوحدات ذات المعنى. بالنسبة إلى السلسلة 3 + 4 * 2، يُصدر المحلّل الرمزي (أو المحلّل المعجمي) أعدادًا وعوامل.
تزيل هذه المرحلة المسافات البيضاء وتصنّف كل مجموعة من المحارف، لذلك لا يتعامل المحلّل النحوي مع البايتات الخام.
نوع الرمز
نمذِج كل رمز باستخدام وسم تعداد وحمولة. وتحمل الأعداد قيمة صحيحة، بينما تحتاج العوامل والأقواس إلى نوعها فقط.
يؤدي الاحتفاظ بالقيمة داخل البنية إلى تجنّب إعادة فحص المصدر لاحقًا.
typedef enum {
TOK_NUM, TOK_PLUS, TOK_MINUS,
TOK_STAR, TOK_SLASH,
TOK_LPAREN, TOK_RPAREN, TOK_EOF
} TokKind;
typedef struct {
TokKind kind;
int value; /* used when kind == TOK_NUM */
} Token;موضع المسح
يجتاز المحلّل المعجمي المصدر باستخدام مؤشر موضع. وتعاين أداة مساعدة صغيرة المحرف الحالي دون استهلاكه، وتعيد '\0' عند النهاية.
تحافظ حسابات المؤشرات على سرعة الماسح وبساطته.
static const char *src;
static char peek(void) {
return *src;
}
static char advance(void) {
return *src++;
}تجاوز المسافات البيضاء
قبل قراءة رمز، نتخلص من المسافات وعلامات الجدولة. وتتولى الدالة القياسية isspace من <ctype.h> معالجة كل محرف فراغ.
تُعد الأسطر الجديدة مسافات بيضاء هنا، لذلك يمكن أن يمتد التعبير عبر عدة أسطر.
#include <ctype.h>
static void skip_ws(void) {
while (isspace((unsigned char)peek()))
advance();
}تحليل عدد معجميًا
عندما يكون المؤشر عند رقم، نجمع الأرقام المتتالية في عدد صحيح. ويؤدي الضرب في عشرة ثم إضافة كل رقم إلى بناء القيمة من اليسار إلى اليمين.
تتوقف الحلقة عند أول محرف ليس رقمًا، تاركةً المؤشر جاهزًا للرمز التالي.
static int lex_number(void) {
int n = 0;
while (isdigit((unsigned char)peek())) {
n = n * 10 + (advance() - '0');
}
return n;
}الدالة next_token
يتجاوز الروتين الأساسي المسافات البيضاء، ثم يوزّع المعالجة وفق المحرف الحالي. وتصبح الأرقام TOK_NUM، بينما يُحوّل كل عامل إلى نوعه الخاص.
ويؤدي الوصول إلى محرف NUL الختامي إلى إنتاج TOK_EOF، وهي الإشارة إلى التوقف.
static Token next_token(void) {
skip_ws();
char c = peek();
if (c == '\0') return (Token){TOK_EOF, 0};
if (isdigit((unsigned char)c))
return (Token){TOK_NUM, lex_number()};
advance();
switch (c) {
case '+': return (Token){TOK_PLUS, 0};
case '-': return (Token){TOK_MINUS, 0};
case '*': return (Token){TOK_STAR, 0};
case '/': return (Token){TOK_SLASH, 0};
case '(': return (Token){TOK_LPAREN, 0};
case ')': return (Token){TOK_RPAREN, 0};
}
return (Token){TOK_EOF, 0};
}تشغيل المحلّل المعجمي
إليكم برنامجًا كاملًا يحلل تعبيرًا إلى رموز ويطبع نوع كل رمز. كما يطبع قيمة الأعداد.
لاحظوا أن الحلقة تنتهي عند قراءة TOK_EOF.
#include <stdio.h>
#include <ctype.h>
typedef enum { TOK_NUM, TOK_PLUS, TOK_STAR, TOK_EOF } TokKind;
typedef struct { TokKind kind; int value; } Token;
static const char *src;
static char peek(void){ return *src; }
static char advance(void){ return *src++; }
static Token next_token(void){
while (isspace((unsigned char)peek())) advance();
char c = peek();
if (c=='\0') return (Token){TOK_EOF,0};
if (isdigit((unsigned char)c)){
int n=0; while(isdigit((unsigned char)peek())) n=n*10+(advance()-'0');
return (Token){TOK_NUM,n};
}
advance();
if (c=='+') return (Token){TOK_PLUS,0};
return (Token){TOK_STAR,0};
}
int main(void){
src = "12 + 3 * 4";
Token t;
do {
t = next_token();
if (t.kind==TOK_NUM) printf("NUM %d\n", t.value);
else if (t.kind==TOK_PLUS) printf("PLUS\n");
else if (t.kind==TOK_STAR) printf("STAR\n");
else printf("EOF\n");
} while (t.kind != TOK_EOF);
return 0;
}رمز واحد للاستبصار
تحتاج المحللات النحوية عادةً إلى فحص الرمز الوشيك قبل استهلاكه. نخزّن رمزًا واحدًا في current عام، ونعيد تعبئته بعد كل مطابقة.
ويكفي هذا الاستبصار برمز واحد لقواعد LL(1) النحوية لدينا.
static Token current;
static void init_lexer(const char *s) {
src = s;
current = next_token();
}
static Token cur(void) { return current; }
static void bump(void) { current = next_token(); }الإبلاغ عن الأخطاء المعجمية
ينبغي ألا يختفي محرف غير معروف — مثل $ أو @ — بصمت. بل يجب على المحلّل المعجمي المتين الإبلاغ عن البايت المخالف وإيقاف التنفيذ.
ويمنع الفشل السريع في المحلّل المعجمي المراحل اللاحقة من رؤية رموز تالفة.
#include <stdio.h>
#include <stdlib.h>
static void lex_error(char c) {
fprintf(stderr, "lex error: unexpected '%c'\n", c);
exit(1);
}العوامل متعددة المحارف
تحتوي اللغات الفعلية على رموز مثل == أو <=. ولتحليلها معجميًا، نعاين محرفًا إضافيًا بعد المحرف الأول.
إذا أكمل البايت التالي العامل، نستهلك المحرفين معًا؛ وإلا نصدر الصيغة ذات المحرف الواحد.
/* fragment: distinguish '=' from '==' */
if (peek() == '=') {
advance();
if (peek() == '=') { advance(); /* TOK_EQ */ }
else { /* TOK_ASSIGN */ }
}لماذا تهم الرموز
من خلال اختزال المحارف إلى رموز، يعمل المحلّل النحوي على تدفق نظيف ومُصنّف. وتصبح أسبقية العوامل والتجميع والأخطاء أسهل في الفهم.
بعد ذلك نمرر هذه الرموز إلى محلّل نحوي بالنزول التكراري.
تحقّق سريع
فكّروا في الرموز التي ينتجها المحلّل المعجمي لرموز التجميع.
مراجعة
بنيتم محلّلًا معجميًا: نوعًا للرمز، ومؤشر مسح، وتجاوزًا للمسافات البيضاء، وتحليلًا معجميًا للأعداد، وموزّع next_token مع استبصار برمز واحد.
وهذه الرموز هي مدخل التحليل النحوي الذي يبني شجرة تركيب منها.
الأسئلة الشائعة
هل درس «تحويل الإدخال إلى رموز» مجاني؟
نعم — نص درس «تحويل الإدخال إلى رموز» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.
ماذا ستتعلم في «تحويل الإدخال إلى رموز»؟
حوّل النص إلى رموز تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟
لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «تحويل الإدخال إلى رموز»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟
نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تحويل الإدخال إلى رموز
- تحليل التعبيرات
- تقييم الشجرة
- إضافة المتغيرات