TAHA
09-22-2009, 03:16 PM
مثال ) برنامه اي بنويسيد كه محتويات خانه اي از حافظه اي را در نظر بگيرد و فاكتوريل انرا محاسبه كند و
در خانه ديگري از حافظه قرار دهد .
fact MACRO n,f ;01 .data ;14
local L1,L2 ;02 n1 db 5 ;15
mov al,1 ;03 f1 db ? ;16
mov cl,2 ;04 .code ;17
L1: cmp cl,n ;05 start: mov ax,@data ;18
jG L2 ;06 mov ds,ax ;19
mul cl ;07 fact n1,f1 ;20
inc cl ;08 mov ah,4ch ;21
jmp L1 ;09 int 21h ;22
L2: mov f,al ;10 end start ;23
endm ;11
.model small ;12
.stack 64 ;13
ماكرو مانند پراسيجري فرض ميكنيم كه call و ret ندارد . علاوه بر اين تفاوت ها نحوه به پايان رسيدن يك ماكرو متفاوت با نحوه به پايان رسيد يك ماكرو است .
خط به خط برنامه فوق را مورد پردازش قرار ميدهيم :
خط اول : ماكرويي با نام fact با دو پارامتر ورودي ميگيرد . تعريف نام ماكرو طبق دستورالعمل زير است
نام ماكرو MACRO پارامترها
قالب شكل فوق يك قالب كلي براي ماكرو است . كه نام ماكرو مانند انتخاب كردن نام متغيرها و برچسب ها كاملا اختياري است . از كلمه MACRO براي مشخص كردن ماكرو بودن دستورات زيرين اين دستور استفاده ميكنيم .
يك ماكرو ميتواند پارامتر داشته باشد و ميتواند پارامتر نداشته باشد دقيقا مانند روالها در برنامه هاي سطح بالا . ياداوري ميكنم كه نقطه ويرگول ( سميكالن ( كه در تمام خطوط ميبينيد تاثيري در پردازش برنامه ندارند كه تنها براي مشخص كردن نام خطوط امده اند . در واقع در يك دستور زبان اسمبلي هر چيزي كه بعد از نقطه ويرگول قرار بگيرد اسمبل نميشود .
خط دوم: با استفاده از دستور local مشخص ميكنيم كه متغيرها و برچسب ها يمان در اين ماكرو محلي است و براي تنها درون همين ماكرو مورد استفاده قرار ميگيرد . در صورتي كه از اين دستور استفاده نكنيد متغير شما محلي نخواهد بود . و برچسب هاي شما نميتوانند هم نام برچسب هاي درون برنامه اصلي باشند .
در ضمن ياداور ميشوم كه دستور local دقيقا بعد از دستور MACRO استفاده ميشود .
خط سوم درون رجيستر يك بايتي al مقدار يك را قرار ميدهد .
خط چهارم دستور فوق مقدار دو را درون رجيستر يك بايتي cl ميريزد .
خط پنجم : در اين خط برچسبي به نام L1 كه قبلا نام ان در local ذكر شده است تعريف ميشود و سرانجام مقدار cl با n مقايسه ميشود
خط ششم : در صورت بزرگتر بود cl از n به برچسب L2 پرش ميكند . درضمن در اين دستور از jg استفاده كرديم تا اگر كاربر مقداري منفي وارد كرد نيز بتوان جوابي براي او در نظر گرفت و برنامه خطا ندهد .
خط هفتم: در صورت درست نبودن مقايسه اي كه در خط شش انجام شد . مقداري كه در al قرار دارد در cl ضرب ميشود و حاصلضرب در al قرار ميگيرد
خط هشتم : در اين خط به مقدار cl يك مقدار اضافه ميشود .
خط نهم : در هر صورت برنامه به برچسب L1 ميپرد .
كليه مراحل فوق تكرار ميشود تا جايي كه بالاخره cl از n بزرگتر شود و برنامه به خط دهم پرش ميكند .
خط دهم : در اين خط كه برچسب L2 نشانگر انست حاصل را كه در al قرار گرفته بود را در f ميريزد و بالاخره در خط يازده .
خط يازده : در اين خط با استفاده از دستور endm كه مخصوص ماكرو است به اسمبلر ميگويد كه ماكرو به پايان رسيده است . بنابراين از ماكرو بيرون امده و به اجراي خط بعد ميپردازد .
اما يادتان باشد كه دستورات خط يك تا يازده همان ابتداي برنامه اجرا نميشوند بلكه در خط 20 كه نام ماكرو اورده شده است اجرا ميشوند يعني اين ده خط جايگزين خط 20 برنامه فوق ميشوند .
استفاده از ماكروها بصورت متوالي در برنامه هاي بزرگ چندان روش جالبي نيست و بهتر است از همان رويه ها استفاده كرد چرا كه به حجم برنامه افزوده ميشود در صورتيكه يك رويه تنها يك بار پردازش ميشود و تنها يك بار تعريف ميشود و خطوط برنامه را زياد نميكند .
اما استفاده از ماكروها را ميتوان به ان صورت در نظر گرفت كه ماكروهاي مورد نظر را در فايلي جداگانه بنويسيم تا ديگر نيازي نداشته باشيم كه در هر برنامه انرا بنويسيم . مثلا ماكرويي كه كاراكتري را چاپ كند تقريبا در تمامي برنامه هايي كه كاربر ميخواهد حاصل را ببيند مورد استفاده قرار ميگيرد . بنابراين اين ماكروها كه اينگونه هستند را در فايلي با پسوند asm ذخيره ميكنيم و سپس تنها در همان خط ابتداي برنامه اي كه ميخواهيم از ماكروها استفاده كنيم از دستور include filename.asm استفاده ميكنيم كه بجاي filename از نام فايل كه براي مجموعه ماكروها با پسوند asm در نظر گرفته ايم استفاده ميكنيم ....
در خانه ديگري از حافظه قرار دهد .
fact MACRO n,f ;01 .data ;14
local L1,L2 ;02 n1 db 5 ;15
mov al,1 ;03 f1 db ? ;16
mov cl,2 ;04 .code ;17
L1: cmp cl,n ;05 start: mov ax,@data ;18
jG L2 ;06 mov ds,ax ;19
mul cl ;07 fact n1,f1 ;20
inc cl ;08 mov ah,4ch ;21
jmp L1 ;09 int 21h ;22
L2: mov f,al ;10 end start ;23
endm ;11
.model small ;12
.stack 64 ;13
ماكرو مانند پراسيجري فرض ميكنيم كه call و ret ندارد . علاوه بر اين تفاوت ها نحوه به پايان رسيدن يك ماكرو متفاوت با نحوه به پايان رسيد يك ماكرو است .
خط به خط برنامه فوق را مورد پردازش قرار ميدهيم :
خط اول : ماكرويي با نام fact با دو پارامتر ورودي ميگيرد . تعريف نام ماكرو طبق دستورالعمل زير است
نام ماكرو MACRO پارامترها
قالب شكل فوق يك قالب كلي براي ماكرو است . كه نام ماكرو مانند انتخاب كردن نام متغيرها و برچسب ها كاملا اختياري است . از كلمه MACRO براي مشخص كردن ماكرو بودن دستورات زيرين اين دستور استفاده ميكنيم .
يك ماكرو ميتواند پارامتر داشته باشد و ميتواند پارامتر نداشته باشد دقيقا مانند روالها در برنامه هاي سطح بالا . ياداوري ميكنم كه نقطه ويرگول ( سميكالن ( كه در تمام خطوط ميبينيد تاثيري در پردازش برنامه ندارند كه تنها براي مشخص كردن نام خطوط امده اند . در واقع در يك دستور زبان اسمبلي هر چيزي كه بعد از نقطه ويرگول قرار بگيرد اسمبل نميشود .
خط دوم: با استفاده از دستور local مشخص ميكنيم كه متغيرها و برچسب ها يمان در اين ماكرو محلي است و براي تنها درون همين ماكرو مورد استفاده قرار ميگيرد . در صورتي كه از اين دستور استفاده نكنيد متغير شما محلي نخواهد بود . و برچسب هاي شما نميتوانند هم نام برچسب هاي درون برنامه اصلي باشند .
در ضمن ياداور ميشوم كه دستور local دقيقا بعد از دستور MACRO استفاده ميشود .
خط سوم درون رجيستر يك بايتي al مقدار يك را قرار ميدهد .
خط چهارم دستور فوق مقدار دو را درون رجيستر يك بايتي cl ميريزد .
خط پنجم : در اين خط برچسبي به نام L1 كه قبلا نام ان در local ذكر شده است تعريف ميشود و سرانجام مقدار cl با n مقايسه ميشود
خط ششم : در صورت بزرگتر بود cl از n به برچسب L2 پرش ميكند . درضمن در اين دستور از jg استفاده كرديم تا اگر كاربر مقداري منفي وارد كرد نيز بتوان جوابي براي او در نظر گرفت و برنامه خطا ندهد .
خط هفتم: در صورت درست نبودن مقايسه اي كه در خط شش انجام شد . مقداري كه در al قرار دارد در cl ضرب ميشود و حاصلضرب در al قرار ميگيرد
خط هشتم : در اين خط به مقدار cl يك مقدار اضافه ميشود .
خط نهم : در هر صورت برنامه به برچسب L1 ميپرد .
كليه مراحل فوق تكرار ميشود تا جايي كه بالاخره cl از n بزرگتر شود و برنامه به خط دهم پرش ميكند .
خط دهم : در اين خط كه برچسب L2 نشانگر انست حاصل را كه در al قرار گرفته بود را در f ميريزد و بالاخره در خط يازده .
خط يازده : در اين خط با استفاده از دستور endm كه مخصوص ماكرو است به اسمبلر ميگويد كه ماكرو به پايان رسيده است . بنابراين از ماكرو بيرون امده و به اجراي خط بعد ميپردازد .
اما يادتان باشد كه دستورات خط يك تا يازده همان ابتداي برنامه اجرا نميشوند بلكه در خط 20 كه نام ماكرو اورده شده است اجرا ميشوند يعني اين ده خط جايگزين خط 20 برنامه فوق ميشوند .
استفاده از ماكروها بصورت متوالي در برنامه هاي بزرگ چندان روش جالبي نيست و بهتر است از همان رويه ها استفاده كرد چرا كه به حجم برنامه افزوده ميشود در صورتيكه يك رويه تنها يك بار پردازش ميشود و تنها يك بار تعريف ميشود و خطوط برنامه را زياد نميكند .
اما استفاده از ماكروها را ميتوان به ان صورت در نظر گرفت كه ماكروهاي مورد نظر را در فايلي جداگانه بنويسيم تا ديگر نيازي نداشته باشيم كه در هر برنامه انرا بنويسيم . مثلا ماكرويي كه كاراكتري را چاپ كند تقريبا در تمامي برنامه هايي كه كاربر ميخواهد حاصل را ببيند مورد استفاده قرار ميگيرد . بنابراين اين ماكروها كه اينگونه هستند را در فايلي با پسوند asm ذخيره ميكنيم و سپس تنها در همان خط ابتداي برنامه اي كه ميخواهيم از ماكروها استفاده كنيم از دستور include filename.asm استفاده ميكنيم كه بجاي filename از نام فايل كه براي مجموعه ماكروها با پسوند asm در نظر گرفته ايم استفاده ميكنيم ....