Control Statements
ခုဆို ကၽြန္ေတာ္တို႕ရဲ႕ ကိုယ္ပိုင္ Assembly language ကိုသုံးၿပီး သခ်ာၤ equation ေတြတြက္လို႕ရေနပါၿပီ။ ဒါေပမဲ့ programming အေရးအႀကီးဆုံးေတြျဖစ္တဲ့ if, switch, for, while တို႕ကို implement လုပ္ဖို႕က်န္ပါေသးတယ္။ ဒါေတြသာရရင္ ကၽြန္ေတာ္တို႕ရဲ႕ language ေလးက programming language တခုအျဖစ္ ေတာ္ေတာ္ ရုပ္လုံးေပၚလာပါလိမ့္မယ္။ခုထက္ထိ ကၽြန္ေတာ္တို႕ ေရးခဲ့သမွ်၊ testing လုပ္သမွ် script ေတြက linear run တဲ့ script ေတြကို ဘဲ ေရးခဲ့ပါတယ္။ ဆိုလိုတာက အစကေန အဆုံးထိ ေတာက္ေလွ်ာက္ run တဲ့ script ေတြပါ။ Virtual Machine ရဲ႕ run လုပ္တဲ့ code ကိုျပန္ၾကည့္မယ္ဆိုရင္၊
void Run(Program& program) { while (true) { Instruction inst = program.Next(); switch (inst.code) { case OP_TALK: printf("Hello, I am simplest language!\n"); break; .................... .................... } } };if တို႕ while တို႕ေရးဖို႕ဆိုရင္၊ program က linear အတိုင္း run ေနတာကို ျပင္ရပါမယ္။ ေလာေလာဆယ္ program.Next() function က nCurrent မွာရွိတဲ့ instruction ကို return ျပန္ပါတယ္။ ဒီေတာ့ ကၽြန္ေတာ္ တို႕က ကိုယ္ run ေစခ်င္တဲ့ code line ကို nCurrent ဆိုတဲ့ variable ထဲထည့္ေပးလိုက္ရင္ run ေစခ်င္တဲ့ line က instruction ကို run ခိုင္းလို႔ရပါတယ္။ ဒီေတာ့ nCurrent variable ကို script ကေနေပးဖို႕ go to ဆိုတဲ့ op-code အသစ္တခုထပ္ထည့္ပါမယ္။
enum OpCode{ OP_TALK, ....................... ....................... OP_GOTO, OP_END };ၿပီးရင္ Program class မွာ nCurrent ကို set လုပ္ဖို႕ function တခုေရးလိုက္ပါ။
class Program{public: vector<Instruction> InstructionList; int nCurrent; ....................... ....................... void SetInstruction(int line_no) { nCurrent = line_no; } };ၿပီးရင္ Virtual Machine မွာသြားၿပီး Goto op-code ကိုေရးဖို႕လိုပါတယ္။
void Run(Program& program) { while (true) { Instruction inst = program.Next(); switch (inst.code) { .................... .................... case OP_GOTO: program.SetInstruction(inst.operand[0]); break; } } };ေပးရမဲ့ line number ကို operand 0 ကေနယူပါမယ္။ ဒါဆို script ထဲမွာ run ခ်င္တဲ့ instruction ရဲ႕ Line number ကို operand 0 ကေနေပးလိုက္ရုံနဲ႔ program ကို execute လုပ္ခိုင္းလို႕ရပါၿပီ။
Note: ဒီေနရာမွာ valid မျဖစ္တဲ့ line number (ဥပမာ၊ -1, 564654 စသည္ျဖင့္) ေပးရင္ error တက္ပါလိမ့္မယ္။ ဒီအတြက္ error checking ေလးတခုေတာ့ Program::SetInstruction() ထဲမွာ ေရးထားသင့္ပါတယ္။
Assembly ရဲ႕ AssemblyCodeTable မွာလဲ OP_GOTO အတြက္ string ID သြားေရးဖို႕လိုပါလိမ့္မယ္။ ဒါမွ Assembler က compile လုပ္ႏိုင္မွာပါ။
static const AssemblyCodeTableEntry AssemblyCodeTable[ASM_ENTRY_COUNT] = { { OP_TALK, "talk" }, ........................ ........................ { OP_GOTO, "goto" }, { OP_END, "end" } };Entry အသစ္တိုးလာတဲ့အတြက္ ASM_ENTRY_COUNT ကိုလဲ တစ္တိုးေပးဖို႔လိုပါလိမ့္မယ္။
const int ASM_ENTRY_COUNT = 17;ကဲဒါဆို goto ဆိုတဲ့ code အသစ္ကို "test.asm" ဆိုတဲ့ assembly file ထဲမွာ သြားစမ္းၾကည့္ရေအာင္။ "test.asm" ထဲမွာ ေအာက္ကလို သြားေရးပါမယ္။
000 put_stack 40001 num 002 goto 0 003 endဒါဆို number 40 ကို screen ေပၚမွာအၿမဲ print ထုတ္ေနပါလိမ့္မယ္။ ဘာနဲ႕သြားဆင္လဲဆိုရင္ while (true) လို infinite loop နဲ႔ဆင္ပါတယ္။ ဒီလို infinite loop ကသိပ္ေတာ့ အသုံး၀င္မွာ မဟုတ္ပါဘူး။
ဒီအတြက္ ခုကၽြန္ေတာ္တို႕ Boolean နဲ႔ logic တြက္တာကို ေရးဖို႕လိုပါတယ္။ ဒီလို true/false တြက္လို႕ရမွ loop ကိုကိုယ္ခ်င္သလို break လုပ္လို႕ရမွာ မဟုတ္လား။ Logic တြက္ဖို႕အတြက္ ခု Logic operator ေတြျဖစ္တဲ့ > (greater than), < (less than), == (equal) တုိ႕ကို ေရးဖို႕လိုပါတယ္။ ဒီအတြက္ ေအာက္က op-code အသစ္ေတြကို ထည့္လိုက္ပါမယ္။
enum OpCode{ ....................... ....................... OP_GREATER_THAN, OP_GREATER_EQUAL, OP_EQUAL, OP_NOT_EQUAL, OP_LESS_THAN, OP_LESS_EQUAL, OP_END };ဒီ op-code ၆ ခုက >, >=, ==, != < နဲ႔ <= sign ေတြအတြက္ပါဘဲ။ Boolean value ေတြျဖစ္တဲ့ true နဲ႔ false အတြက္ ကိုယ္ပိုင္ definition ေတြေရးဖို႕လိုပါလိမ့္မယ္။
enum Boolean { _FALSE = 0, _TRUE = 1 };ဒါဆို Virtual Machine ရဲ႕ Run() function မွာ ကၽြန္ေတာ္တို႕ရဲ႕ op-code အသစ္ေတြသြား ေရးလို႕ရပါၿပီ။ ကဲေရးၾကည့္ရေအာင္ပါ။
void Run(Program& program) { while (true) { Instruction inst = program.Next(); switch (inst.code) { .................... .................... case OP_GREATER_THAN: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 > Data1) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_GREATER_EQUAL: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 >= Data1) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_EQUAL: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 == Data1) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_NOT_EQUAL: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 != Data1) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_LESS_THAN: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 < Data1) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_LESS_EQUAL: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 <= Data1) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; } } };Code မ်ားေပမဲ့ ဘာမွ ေထြေထြထူးထူး ေရးထားတာ မရွိပါဘူး။ Stack ေပၚက data ႏွစ္ခုကို ယူၿပီး သက္ဆိုင္ရာ sign ေတြနဲ႕ တိုက္စစ္လိုက္တာပါ။ ၿပီးရင္ stack ေပၚကို true သို႕ false ျပန္တင္ေပးလိုက္တာပါ။ ခု အသစ္ op-code ေတြအတြက္ Assembly table ထဲမွာလဲသြားေရးဖို႔ လိုပါလိမ့္မယ္။ ဒါမွ Assembler က compile လုပ္ႏိုင္မွာပါ။ ဒီအတြက္ေတာ့ စာဖတ္သူ ကိုယ္တိုင္ဘဲ စမ္းေရးၾကည့္ေစခ်င္ပါတယ္။ ၿပီးရင္ ASM_ENTRY_COUNT ကိုလဲ တိုးေပးဖို႕ မေမ့ပါနဲ႕။
>= တို႕ == တို႕လို sign ေတြအျပင္ && (and), || (or), နဲ႔ ! (not) တို႕လဲ ေရးဖို႕လုိပါလိမ့္မယ္။ ဒါမွ ႏွစ္ခုထက္ပိုတဲ့ Boolean ေတြကို ေပါင္းတြက္လို႕ရမွာ မဟုတ္လား။ ကဲေရးၾကည့္ရေအာင္ပါ။ Op-code definition ထဲမွာသြားေရးပါမယ္။
enum OpCode{ ....................... ....................... OP_AND, OP_OR, OP_NOT, OP_END };ၿပီးရင္ Virtual Machine ရဲ႕ Run() function ထဲမွာ ဒီသုံးခုကို သြားေရးလိုက္ပါအုံးမယ္။
void Run(Program& program) { while (true) { Instruction inst = program.Next(); switch (inst.code) { .................... .................... case OP_AND: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 == _TRUE && Data1 == _TRUE) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_OR: Data1 = program.PopStack(); Data2 = program.PopStack(); if (Data2 == _TRUE || Data1 == _TRUE) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; case OP_NOT: Data1 = program.PopStack(); if (Data1 == _FALSE) program.PushStack(_TRUE); else program.PushStack(_FALSE); break; } } };ဒီေနရာမွာ ေရးထားတာလဲ logic operators ေတြေရးသလိုပါဘဲ၊ stack ေပၚက data ႏွစ္ခုကို ယူၿပီး လိုခ်င္တဲ့ and တို႕ or တို႕နဲ႔တိုက္စစ္လိုက္ပါတယ္။ ၿပီးရင္ true/false ျပန္ၿပီး stack ေပၚကို တင္လိုက္ပါတယ္။ ၿပီးရင္ Assembly Code Table မွာ and၊ or နဲ႕ not အတြက္ entry ေတြကို ထည့္ဖို႕လဲ မေမ့ပါနဲ႕။
Logic operator ေတြေရးၿပီးသြားရင္ ကၽြန္ေတာ္တို႕ conditional GOTO ကိုေရးလို႔ရၿပီ။ Conditional GOTO ဆိုတာ stack ေပၚက value က true ျဖစ္မွ ေပးထားတဲ့ line ကို GOTO ကသြားမွာပါ။ တကယ္လို႔ false ဆိုရင္ GOTO ေပးထားတဲ့ line ကိုမသြားဘဲ ေအာက္တလိုင္းကိုဘဲ ဆင္းပါမယ္။ အဲဒီ op-code ကို if-goto လိ႔ုနာမည္ေပးထားပါမယ္။ if not go to ကိုလဲ တပါတည္း ေရးထားရေအာင္။ if-not-goto ကေတာ့ if-goto ရဲ႕ ဆန္႔က်င္ဘက္ေပါ့။ သူက false ျဖစ္မွ goto ေပးထားတဲ့ line ကိုသြားပါမယ္။ ကဲ if-goto နဲ႔ if-not-goto အတြက္ op-codes ေတြထည့္လိုက္ပါမယ္။
enum OpCode{ ....................... ....................... OP_IF_GOTO, // if go to OP_IFN_GOTO, // if not go to OP_END };ၿပီးရင္ Run() function ထဲမွာ သူတို႔အတြက္ implementation ကိုသြားေရးပါအုံးမယ္။
void Run(Program& program) { while (true) { Instruction inst = program.Next(); switch (inst.code) { .................... .................... case OP_IF_GOTO: if (program.PopStack() == _TRUE) program.SetInstruction(inst.operand[0]); break; case OP_IFN_GOTO: if (program.PopStack() == _FALSE) program.SetInstruction(inst.operand[0]); break; } } };ေရးထားတာ goto အတိုင္းပါဘဲ။ ဒါေပမဲ့ if တခ်က္ခံစစ္ၿပီးမွ operand 0 ထဲကို Line number ကိုေပးသြားမွာျဖစ္ပါတယ္။ ဒါဆိုရင္ high-level language က if-else ကို assembly language သုံးၿပီးဘယ္လိုေရးမလဲ ၾကည့္ရေအာင္။
C မွာေရးရင္ -
if (condition){ // do something } else { // do something else }Script မွာေရးရင္ -
// evaluate conditionifn_goto A // A corresponds to an appropriate value to reach the position A // do something goto B A: // do something else B:While loop ကိုဘယ္လိုေရးမလဲ ၾကည့္ရေအာင္၊
C မွာေရးရင္ -
while (condition){ // do something }Script မွာေရးရင္ -
A:// evaluate condition Ifn_goto B // do something goto A B:Do-While loop ကိုကၽြန္ေတာ္တို႕ Assembly language မွာဘယ္လိုေရးမလဲ ၾကည့္ရေအာင္၊
C မွာေရးရင္ -
do{ // do something } while (condition);Script မွာေရးရင္ -
A:// do something // evaluate condition if_goto Aကဲဒါဆို conditional statement (if) နဲ႔ looping (while) တို႕ကိုဘယ္လိုေရးရမလဲ သိသြားပါၿပီ။ ခုကၽြန္ေတာ္ တို႕ ေရးခဲ့ၿပီးသေလာက္ testing လုပ္ၾကည့္ရေအာင္ပါ။ Testing အတြက္ ၁ ကေန ၂၀ အတြင္းက number ေတြထဲမွာ စုံကိန္းေတြကိုဘဲ screen ေပၚကို Print လုပ္ၾကည့္ရေအာင္။ C မွာအဲဒီ testing code ကိုေရးရင္ ေအာက္ကအတိုင္း ေရးရမယ္ ထင္ပါတယ္။
for (int i = 0; i < 20; i++) { if (i % 2 == 0) cout i; }ကဲ Assembly မွာေရးၾကည့္ရေအာင္ :)
// initialize i variable to 0. Address: 0000 put_mem 0 0 // perform i % 2 001 push_stack 0 002 put_stack 2 003 modulus // test (i %2) == 0 004 put_stack 0 005 equal // print number 006 ifn_goto 8 007 push_stack 0 008 num // do i++ 009 push_stack 0 010 put_stack 1 011 add 012 pop_stack 0 // check i < 20 013 push_stack 0 014 put_stack 20 015 less_than // perform looping 016 if_goto 1 017 endအေပၚက assembly code ေရးရတာ လြယ္တယ္မဟုတ္လား :) ကိုယ္ပိုင္ေရးလာခဲ့တဲ့ assembly language မို႔ ေလ့လာစရာမလိုပါဘူး။ ကၽြန္ေတာ္တို႕ C နဲ႔ ေရးထားတဲ့ code ကိုဘဲ တိုက္ရိုက္ဘာသာျပန္ၿပီး ေရးလိုက္တာပါ။ ၿပီးရင္ testing လုပ္ၾကည့္ပါအုံး။ ခုဆို ကၽြန္ေတာ္တို႕ language က သခ်ာၤအတြက္အခ်က္တင္ မကဘဲ၊ တကယ့္ programming language တခုနီးပါးအတိုင္း ေရးႏိုင္လာၿပီ ျဖစ္ပါတယ္။
No comments:
Post a Comment