Virtual Machines
الآلات الإفتراضية
معلومة اليوم/
إذا لم تستطع صنع آلة فإنه بوسعك أن تحاكيها.
لتكن العبارة السابقة هي محور هذا الموضوع.
ما أطمح إلية أن يكون هذا الموضوع بمثابة عصا سحرية تفتح مجالك البرمجي للإبداع...
لماذا Virtual Machines؟
هل تعرف Java Virtual Machine (JVM) ؟
عبارة عن برنامج يقوم بعمل واجهة بينك وبين الحاسب بحيث يمكنك من التعامل معه.
أكثر من ذلك يمكنك من التعامل مع أكثر من نظام تشغيل.
وأكثر من ذلك يمكنك من التعامل مع أكثر من آلة.
بينما لغة Java هي نفسها لم تتغير بحيث أن برنامجك الواحد يمكنه العمل على أغلب منصات العمل.
متى تحتاج كمبرمج VM؟
عن نفسي : درست مقرر Compiler Design وكتبت لغة برمجة بسيطة جداً حيث تأخذ النص الأصلي وتحوله إلى لغة قريبة من لغة التجميع وانتهى المقرر.
والمشكلة ظهرت عندما أردت أن أنفذ البرنامج (كيف؟) كيف أحول الملف إلى صيغة exe.
وبينما أنا أبحث عثرت على VM.
- وأيضا كنت أتتبع كود لـ محرك SQL ووجده هو أيضا يستخدم VM
كيف أكتب VM خاص بي؟
لست أبالغ أن برمجة VM هي من أسهل مجالات البرمجة لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن
لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن لكن
الأهم هو فهم طبيعة عمل الآلة .
لحسن الحض أن هناك آلات سهلة يمكن البدء بها وستكون مفيدة بإذن الله.
دعنا من لغات البرمجة ولنذهب إلى بنية الحاسب نفسة.
مبدئياً/ سنأخذ آلة المكدس stack machine وتحتوي على:
معالج processor
ذاكرة memory
تعليمة instuction
بنية المعالج ستكون كالتالي
struct processor{
instruction IR, /* instruction reg */
int PC, /* Program Counter */
int SP /* Stack Pointer */
} CPU;أما التعليمة فتمثل كالتالي
struct instruction
{
int opcode; /* قيمة التعليمة*/
int arg; /* المعامل */
};أما الذاكرة فهي عبارة عن مصفوفتين
int stack[1024]; /* تستخدم لأجل تنفيذ العمليات */ instruction code[1024]; /* لتخزين الكود */
أما إجرائية عمل الآلة فهي كالتالي:
BEGIN code := fetch_from_file(); (* تحويل التعليمات من نصوص إلى أكواد *) CPU.PC := 0; (* عنوان أول تعليمة *) LOOP CPU.IR := code[CPU.PC]; (* جلب التعليمة من الذاكرة *) CPU.PC++; (* زيادة مؤشر العنوان للتالي *) Execute(CPU.IR); (* تنفيذ التعليمة *) END END.
بعد اللمحة البسيطة عن عمل الألة.
لنذهب إلى البرمجة/
هناك مايسمى تمثيل داخلي (أي داخل البرنامج)
تمثل كل تعليمة برقم معبن بحيث يسهل التعامل معها.
وهناك تمثيل خارجي (خارج البرنامج)
تمثل كل تعليمة بنص.
تتم عملية جلب التعليمات من الملف ونقلها إلى مصفوفة الأكواد.
ثم يبداء العمل داخل التكرار الموضح
سوف أكتب مجوعة من التعليمات وتنفيذها
read إقرأ من سطر الأوامر
write أكتب إلى الشاشة
add إجمع
sub إطرح
mul اضرب
div إقسم
وتتم كالتالي :
stack[CPU.SP-1] = stack[CPU.SP-1] [+-/*] stack[CPU.SP--];
eq مقارنة
stack[CPU.SP-1] = stack[CPU.SP-1] == stack[CPU.SP--] ? 1 : 0;
lt مقارنة
stack[CPU.SP-1] = stack[CPU.SP-1] < stack[CPU.SP--] ? 1 : 0;
gtمقارنة
stack[CPU.SP-1] = stack[CPU.SP-1] > stack[CPU.SP--] ? 1 : 0;
ld حمل إلى stack
stack[++CPU.SP] = CPU.IR.arg;
st خزن في stack
stack[CPU.IR.arg] = stack[CPU.SP--];
goto إنقل تنفيذ البرنامج إلى
CPU.PC = CPU.IR.arg;
jz إنقل تنفيذ البرنامج بشرط
if(stack[CPU.SP] == 0) CPU.PC = CPU.IR.arg;
halt إنهاء البرنامج
ولضيق الوقت أكتفي بنقل هذا الكود.
على أنه كان بودي الإسهاب في هذا الموضوع لأعطية حقه
void fetch_execute_cycle()
{ do { /* Fetch */
ir = code[pc++];
/* Execute */
switch (ir.op) {
case HALT : printf( "halt\n" ); break;
case READ_INT : printf( "Input: " );
scanf( "%ld", &stack[ar+ir.arg] ); break;
case WRITE_INT : printf( "Output: %d\n", stack[top--] ); break;
case STORE : stack[ir.arg] = stack[top--]; break;
case JMP_FALSE : if ( stack[top--] == 0 )
pc = ir.arg;
break;
case GOTO : pc = ir.arg; break;
case DATA : top = top + ir.arg; break;
case LD_INT : stack[++top] = ir.arg; break;
case LD_VAR : stack[++top] = stack[ar+ir.arg]; break;
case LT : if ( stack[top-1] < stack[top] )
stack[--top] = 1;
else stack[--top] = 0;
break;
case EQ : if ( stack[top-1] == stack[top] )
stack[--top] = 1;
else stack[--top] = 0;
break;
case GT : if ( stack[top-1] > stack[top] )
stack[--top] = 1;
else stack[--top] = 0;
top--;
break;
case ADD : stack[top-1] = stack[top-1] + stack[top];
top--;
break;
case SUB : stack[top-1] = stack[top-1] - stack[top];
top--;
break;
case MULT : stack[top-1] = stack[top-1] * stack[top];
top--;
break;
case DIV : stack[top-1] = stack[top-1] / stack[top];
top--;
break;
case PWR : stack[top-1] = stack[top-1] * stack[top];
top--;
break;
default : printf( "%sInternal Error: Memory Dump\n" );
break;
}
}
while (ir.op != HALT);
}بعد هذا أستطيع أن أفول مبروك عليك هذة المحاكاة وعقبال عمل محاكاة لأجهزة أخرى تنفع بها المسلمين.
سوف أكون مستعد بما أستطيع لإجابة على أسئلتكم.
وأود أن أنبه إلى من يكون عنده مصادر موسعة عن الموضوع إن لا يبخل علينا فهي مهمة بالنسبة لي ولغيري
أرجوكم سامحوني على الركاكة في الاسلوب لأنه أول موضوع كبير بالنسبة لي