اینجا هستید : safarionline.ir / books / pumr / ch04

فصل ۴ - The Concept of Action

action لازمه‌ی یک برنامه‌ی کامپیوتری است، یعنی برنامه باید با دیتا کاری انجام دهد، حتی اگر این کار این باشد که انتخاب کند کاری انجام ندهد!

مثال. برنامه‌ای که هیچ کاری انجام نمی‌دهد.

action ها توسط statement ها توصیف می‌شوند. statement ها یا ساده هستند مثل انتساب و یا اینکه ساختاریافته‌اند.

ابتدایی‌ترینِ statement ها assignment statement است. این statement مقدار محاسبه شده‌ی جدید را، که توسط یک expression مشخص می‌شود، به یک variable اختصاص می‌دهد و فرم آن به شکل زیر است:

:= بیانگر انتساب است و نباید با عملگر رابطه‌ای = اشتباه گرفته شود. statement A := 5 به صورت «مقدار کنونی A با ۵ جایگزین شد» یا به صورت ساده‌تر «A، ۵ می‌شود.» خوانده می‌شود.

تصویر زیر را ببینید تا بحث را پی بگیریم:

یک variable ممکن است یک entire variable (متغیر کامل) باشد که کل فضای ذخیره‌سازی یک نوع داده‌ی ساده، structured، و یا pointer را نشان می‌دهد. در مورد انواع داده‌ای ساخت یافته یا structured، یک متغیر می‌تواند یک component variable (متغیر مولفه) یا یک buffer variable (متغیر بافر) باشد که نشان دهنده‌ی یک مولفه از data storage است. در حالتِ نوع داده‌ایِ اشاره‌گر یک متغیر ممکن است یک identified variable باشد که فضای ذخیره‌سازی را به صورت غیر مستقیم توسط یک اشاره‌گر نشان می‌دهد.

یک expression از عملگرها و عملوندها تشکیل شده است. یک عملوند می‌تواند یک ثابت، یک متغیر، array parameter bound (که در فصل ۱۱ در مورد آن بحث می‌کنیم.) و یا function designator باشد. function designator مشخص کننده‌ی activation یک تابع است.

کادر زیر را ملاحظه کنید تا فرق بین چند مفهوم را متوجه شوید.

Sqrt            function identifier
Sqrt(X)         function designator
Sqrt(X) + 5     expression

در هنگام اجرای برنامه همین Function Designator باعث فراخوانی (call) تابع می‌شود.

💡 همان‌طور که دستور فراخوانی یک رویه را Procedure Statement می‌نامیم، عبارت فراخوانی یک تابع نیز در اصطلاح رسمی پاسکال Function Designator نام دارد. دلیل تفاوت این دو اصطلاح آن است که فراخوانی یک رویه یک statement است، در حالی که فراخوانی یک تابع یک expression (یا دقیق‌تر، یکی از اجزای تشکیل‌دهندهٔ یک expression) محسوب می‌شود.

در پیوست A توابع از پیش تعریف شده را لیست کرده‌ایم و در فصل ۱۱ در مورد تعریف تابع توسط برنامه‌نویس بحث می‌کنیم.

یک expression قانونی‌ای است برای محاسبه‌ی یک مقدار بر مبنایِ قواعدِ قراردادیِ جبر برای ارزیابی عملگرها و اولویت عملگرها از چپ به راست. expression ها از :

  1. factor ها
  2. term ها
  3. simple expression ها

تشکیل شده‌اند.

فاکتورها اول ارزیابی می‌شوند و از ثابت‌های تنها یا متغیرها یا function designator ها یا array-parameter bound ها یا set constructor ها تشکیل شده‌اند. همچنین ممکن است که یک فاکتور از اعمال عملگر not بر یک فاکتور دیگر ایجاد شود که بیانگر یک مقدار Boolean است. فاکتور ممکن است یک expression را در بر داشته باشد که بین دو پرانتز محصور است. در این حالت این فاکتور به صورت مستقل از عملگر‌هایی که قبل یا بعدش می‌آیند ارزیابی می‌شود.

بعد از factor ها term ها ارزیابی می‌شوند. term ها از یک مجموعه فاکتور که با multiplying opertaor ها یعنی * ، / ، div ، mod و and جدا شده‌اند و یا یک فاکتور ساده تشکیل شده‌اند. این عملگرها گرچه همه کار ضرب را انجام نمی‌دهند ولی در زمره‌ی «عملگرهای ضربی» قرار می‌گیرند چون همگی اولویت برابری با عمل ضرب دارند.

simple expression ها بعد از term ها ارزیابی می‌شوند. simple expression ها از یک توالی از term ها که با adding operator ها یعنی + ، - ، و یا or از هم جدا شده‌اند، و یا یک term ساده، تشکیل شده‌اند. به صورت دلخواه یک عملگر sign-inversion یعنی + یا - می‌تواند قبل از اولین term یک simple expression بیاید.

مثال از sign-inversion-operator

نهایتا expression ها ارزیابی می‌شوند. این مرحله از یک simple expression و یک عملگر رابطه‌ای یعنی = ، <>، < ، <= ، > ، >= و یا in و یک simple expression دیگر، یا به سادگی یک simple expression تنها تشکیل می‌شود.

مثال:

2 * 3 - 4 * 5       =   (2*3) - (4*5)       = -14
15 div 4 * 4        =   (15 div 4) * 4      =  12
80 / 5 / 3          =   (80/5) / 3          =   5.333
4 / 2 * 3           =   (4/2) * 3           =   6.000
sqrt(sqr(3) + 11 * 5)                       =   8.000    

هر وقت در مورد اولویت عملگرها دچار تردید شدید از جدول زیر استفاده کنید:

boolean expression ها این ویژگی را دارند که ممکن است مقدارشان قبل از ارزیابی کل expression مشخص شود. به عنوان مثال فرض کنید X=0:

(X > 0) AND (X < 10)

در این صورت بعد از محاسبه‌ی اولین فاکتور مقدار expression مشخص است که False است و نیازی به ارزیابی فاکتور دوم نیست. این که فاکتور دوم ارزیابی بشود یا نه بستگی به پیاده ‌سازی دارد. این به آن معنی است که برنامه‌نویس باید مطمئن شود که فاکتور دوم، مستقل از مقدار فاکتور اول، به درستی تعریف شده است. از این رو اگر فرض کنیم که اندیس‌های آرایه‌ی A از ۱ تا ۱۰ است، مثال زیر خطا دارد:

I := 0;
REPEAT
    I := I + 1
UNTIL (I > 10) OR (A[I] = 0);

توجه دارید که اگر هیچ یک از عناصر آرایه صفر نباشد دسترسی به A[11] رخ خواهد داد که خطا است.

غیر از مورد file variables که آن را در فصل ۹ مطالعه خواهیم کرد، انتساب در مورد متغیرهای همه‌ی انوع امکان پذیر است. variable (یا تابع) و expression باید از نظر انتساب compatible باشند یا به عبارت دیگر assignment compatible باشند.

مواردی که در آن انتساب ممکن است به شرح زیر است:

  1. variable و expression از یک نوع باشند، مگر اینکه آن نوع، نوع فایل باشد یا شامل یک نوع فایل به عنوان یک مولفه component در یک نوع ساختاریافته یا structured دیگر باشد.

  2. variable از نوع Real باشد و expression از نوع Integre.

  3. variable و expression از همان نوع یا subrange هایی از همان نوع oridnal باشند، و مقدار expression باید در بازه‌ی بسته‌ای قرار گیرد که توسط نوع متغیر تعیین شده است. به بیان دیگر، مقدار عبارت باید یکی از مقادیر مجاز نوع متغیر باشد:

    TYPE
        Digit = 0..9;
        Small = 3..7;
    VAR
        D: Digit;
        S: Small;
    
    {..........}
    
    D := S;
    
  4. variable و expression از یک نوع set باشند (فصل ۸) یا از نوع set باشند و type اصلی آن ها یکی و یا subrange هایی از همان نوع ordinal باشد. یا هر دو نوع باید packed باشند، یا هیچ یک packed نباشد.

  5. variable و expression از نوع String و با همان تعداد عنصر باشند. (یعنی طول رشته‌های برابر باشد.) String در اینجا یعنی آرایه‌ای از کاراکترها.   ⬅ مثال

    ❗ در انتساب رشته‌ها در پاسکال استاندارد طول رشته‌ی مبدا و مقصد باید یکی باشد. حتی رشته‌ی کوچکتر را نمی‌توان در رشته‌ی بزرگتر assign کرد.

انتساب‌های زیر assignment های معتبری در زبان پاسکال هستند:

Root1  := Pi*X/Y;
Root2  := -Root1;
Root3  := (Root1 + Root2) * (1.0 + Y);
Danger := Temp > VaporPoint;
Count  := Count + 1;
Degree := Degree + 10;
SqrPr  := Sqr(pr);
Y      := Sin(X) + Cos(Y);

نوع دیگری از statement های ساده، procedure statement ها هستند که یک named procedure را فعال می‌کنند. named procedure زیر برنامه‌ای است که مجموعه‌ی دیگری از عملیات، که باید روی data انجام شود، را مشخص می‌کند. در این کتاب تاکنون از پروسیجرهای Read و ReadLn و Write و WriteLn به منظور اجرای ورودی و خروجی استفاده کرده‌ایم. در فصل ۱۱ مبحث procedure statement ها را به تفصیل بررسی می‌کنیم.

compound statement ها یا عبارت‌های ترکیبی می‌گویند که statement های سازنده‌ی آن باید به همان ترتیبی که نوشته شده‌اند اجرا شوند. نمادهای BEGIN و END به عنوان پرانتز برای statement ها عمل می‌کنند و چند دستور را در یک گروه قرار می‌دهند. در نظر داشته باشید که statement part یا بدنه‌ی program به شکل compound statement است.

مثال

🔔 پاسکال از ; برای جدا کردن statement ها استفاده می‌کند و نه به عنوان علامتی برای پایان statement ها. یعنی semicolon جزئی از statement نیست. قوانین صریح در مورد semicolon در syntax پیوست D منعکس شده است. اگر برنامه‌نویس در مثال قبلی بعد از دومین statement یک ; گذاشته باشد، این به معنای آن است که یک empty statement که بیانگر no action است بین semicolon و END وجود دارد. این موضوع مشکلی ایجاد نمی‌کند چون وجود یک empty statement در این محل مجاز است. با این حال، قرار دادن نادرست semicolon می‌تواند دردسرساز باشد؛ برای نمونه به مثال مربوط به دستور if در بخش 4.E توجه کنید.

repetitive statement ها می‌گویند که چند statement مشخص به صورت پی در پی اجرا شوند. اگر تعداد تکرار از قبل مشخص باشد for statement بهترین ساختار برای این کار است، در غیر این صورت از repeat statement یا while statement استفاده کنید.

  1. while statement. سینتکس دیاگرام while statement به صورت زیر است:

    statement ای که بعد از DO می‌آید صفر بار یا بیشتر اجرا می‌شود. expression ای که عمل تکرار را کنترل می‌کند باید از نوع Boolean باشد. قبل از اینکه statement اجرا شود، expression ارزیابی می‌شود. اگر expression به True ارزیابی شود statement اجرا می‌شود و در غیر این صورت while statement خاتمه می‌یابد. از آنجایی که expression برای هر بار تکرار ارزیابی می‌شود بهتر است که دقت کافی مبذول نمایید و expression را تا حد ممکن ساده نگه دارید.

    مثال

    برنامه‌ی 4.3 که در زیر آمده است عدد Real به نام X را به توان Y می‌رساند. Y یک عدد Integer نامنفی است. یک نسخه‌ی ساده‌تر و آشکارا درست از برنامه، با حذف while statement درونی به دست می‌آید: متغیر Result از Y بار ضرب در X به دست می‌آید. در الگوریتم کتاب که به مراتب موثرتر و کارآمدتر است از مفهوم loop invariant استفاده شده است که نیاز به تعمق بیشتری دارد. #Think   ⬅ مثال 4.3

    💡 loop invariant یعنی رابطه یا حقیقتی‌ که با وجود تغییر متغیرهای حلقه، پس از هر بار اجرای حلقه همچنان برقرار می‌ماند.

  2. repeat statement. سینتکس دیاگرام repeat statement به صورت زیر است:

    توالی statement هایی که بین REPEAT و UNTIL وجود دارد حداقل یک بار اجرا می‌شود. بعد از هر بار اجرای این توالیِ statement ها، یک boolean expression ارزیابی می‌شود. اگر این مقدار به True ارزیابی شود اجرای حلقه خاتمه می‌یابد. همانند while statement اینجا هم چون expression در هر بار اجرای حلقه باید ارزیابی شود آن را تا حد ممکن ساده نگه دارید.

    مثال 4.4. اگر N > 0 باشد این برنامه به درستی کار می‌کند ولی اگر N <= 0 باشد نه. بررسی کنید چرا اینگونه است و چرا نسخه‌ی while statement همین برنامه در هر صورت درست کار می‌کند.

    🔔 repeat statement یک توالی از statement ها دارد که باید آن را به ترتیب اجرا کند. در اینجا نوشتن BEGIN و END در ابتدا و انتهای statement ها گرچه غلط نیست ولی اضافه است. مثال

  3. for statement. حلقه‌ی for statement بیان می‌کند که یک statement به صورت پی در پی اجرا شود و هر بار control variable حلقه به صورت اتوماتیک تغییر کند. سینتکس دیاگرام for statement به صورت زیر است:

    مثال 4.5

    control variable، که بعد از FOR می‌آید باید از یک نوع ordinal باشد و در همان بلاکی اعلان شده باشد که for statement قرار دارد.

© کلیه‌ی حقوق برای safarionline.ir محفوظ است.