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

فصل ۴ - The Concept of Action

➡ فهرست مطالب

  1. فصل ۴ - The Concept of Action
  2. assignment statement
  3. variables
  4. expression
    1. factors
    2. terms
    3. simple expression
    4. evaluating of expressions
  5. variables and expressions and assignment
  6. procedure statement
  7. compound statement and empty statement
  8. repetitive statements
    1. while statement
    2. repeat statement
    3. for statement
  9. conditional statements
    1. if statement
    2. case statement
  10. with statement
  11. goto statement
  12. نکات متفرقه
    1. دسته‌بندی statement ها
    2. statement sequence

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

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

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

assignment statement

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

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

variables

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

expression

یک 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 ها

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

factors

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

terms

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

simple expression

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

مثال از sign-inversion-operator

evaluating of expressions

نهایتا، 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] رخ خواهد داد که خطا است.

variables and expressions and assignment

غیر از مورد 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);

procedure statement

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

compound statement and empty 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 statements

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

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 یعنی رابطه یا حقیقتی‌ که با وجود تغییر متغیرهای حلقه، پس از هر بار اجرای حلقه همچنان برقرار می‌ماند.

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 ها گرچه غلط نیست ولی اضافه است. مثال

for statement

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

مثال 4.5

❗ control variable، بعد از FOR می‌آید و باید از یک نوع ordinal باشد و در همان بلاکی اعلان شده باشد که for statement قرار دارد. مقدار initial و final باید از یک نوعِ ordinal سازگار با متغیر کنترل حلقه باشند. control variable نباید توسط component statement تغییر داده شود. این مطلب یعنی قرار گرفتن متغیر کنترل حلقه در سمت چپ assignment ها، در پروسیجرهای Read و ReadLn، متغیر کنترل یک for statement دیگر، خواه اینکه مستقیما در for statement باشد یا اینکه در پروسیجر و تابعی که در همان بلاک اعلان شده، ممنوع است.
  ⬅ مثال

مقدار initial و final فقط یکبار محاسبه می‌شود. در مورد TO اگر مقدار اولیه بزرگتر از مقدار نهایی باشد component statement اجرا نمی‌شود. همین مطلب در مورد DOWNTO نیز اتفاق می‌افتد با این تفاوت که اگر مقدار اولیه از مقدار نهایی کوچکتر باشد.

If the component statement is executed, it is an error if either the initial value or final value cannot be assigned to the control variable.

💡 مقدار control variable در صورت خروج طبیعی از for statement تعریف نشده است و کامپایلرها ممکن است رفتارهای متفاوتی در این مورد پیشه کنند. برنامه‌نویس به هیچ وجه نباید روی مقدار متغیر کنترل حلقه بعد از پایان حلقه حدس و گمان بزند و بر مبنای آن کد بنویسد.

مثال 4.6. توضیحات در متن برنامه #Think

مثال 4.7. توضیحات در متن برنامه #Think

مثال 4.8. توضیحات در متن برنامه #Think

❗ در پاسکال استاندارد CONTINUE و BREAK وجود ندارد. Wirth معتقد بود که FOR باید یک نقطه‌ی آغاز و یک نقطه‌ی پایان داشته باشد و وجود این دو statement باعث اختلال در فلسفه‌ی وجودی FOR می‌شود.

conditional statements

conditional statement تنها یک statement از مجموعه‌ی statement های سازنده‌اش را برای اجرا انتخاب می‌کند. پاسکال دو نوع conditional statement دارد، if و case.

if statement

if statement بیان می‌کند که یک statement تنها در صورتی اجرا بشود که یک شرط بخصوص (boolean expression) به True ارزیابی شود. اگر شرط False باشد، یا هیچ statement ای اجرا نمی‌شود یا statement ای که بعد از ELSE آمده است اجرا می‌شود. سینتکس دیاگرام if statement به صورت زیر است:

expression ای که بین IF و THEN قرار دارد باید از نوع Boolean باشد. توجه داشته باشید که می‌توان به حالت اول یعنی IF بدون ELSE، به عنوان مختصرنویسی‌ای از حالت دوم نگاه کرد:

IF Condition THEN           { | first form               }
    statement;              { | first form               }

{--------------------------------------------------------}

IF Condition THEN           { | second form }
    statement               { | second form }
ELSE                        { | second form }
    alternative-statement;  { | second form }

{--------------------------------------------------------}

IF Condition THEN           { | extended first form      }
    statement               { | extended first form      }
ELSE                        { | به شرط حذف ; قبل از ELSE }
    ;                       { | empty statement          }
}

⛔ هرگز قبل از ELSE سمی‌کالن ; نگذارید. دلیلش روشن است. بعد از THEN فقط یک statement می‌آید که می‌تواند ساده و یا از نوع compound statement باشد. حال اگر قبل از ELSE یک ; بگذاریم در واقع یک statement seperator گذاشته‌ایم و این به معنای پایان if statement است. در این حالت بلافاصله ELSE آمده است که statement نیست و فقط بخشی از دستور IF است، لذا کامپایلر خطا می‌دهد.

🔴 با توجه به مطلب نوشته شده در کادر بالا این کد اشتباه است:

IF P THEN
BEGIN
    S1;
    S2;
    S3
END;      { ; statement seperator is not syntatically allowed before else }
ELSE
    S4

🔴 یک خطای گمراه کننده‌ی دیگر می‌تواند به شکل زیر باشد. در این کد statement ای که توسط IF کنترل می‌شود یک empty statement است که بین THEN و ; قرار گرفته است. از این رو compound statement ای که بعد از if statement آمده است، همیشه اجرا می‌شود.

IF P THEN;      { end of if statement       }
BEGIN           
    S1;         { | this compund statement  }
    S2;         { | will be executed        }
    S3          { | always.                 }
END             

🔴 ابهام‌هایی که در تفسیر IF های تو در تو و این که کدام ELSE مربوط به کدام IF است را با compound statement و استفاده از BEGIN و END مرتفع کنید. به عنوان مثال:

IF Expression1 THEN
    IF Expression2 THEN
        statement1
    ELSE
        statement2

{-----------------------------------------}

IF Expression1 THEN
BEGIN
    IF Expression2 THEN
        statement1
    ELSE
        statement2
END

💡 به عنوان قاعده‌ای کلی، هر ELSE مربوط به نزدیک‌ترین IF است.   ⬅ مثال

🔴 به شما هشدار داده می‌شود که if statement ای که با بی‌دقتی نوشته شده باشد می‌تواند بسیار پرهزینه باشد. به عنوان مثال فرض کنید که n شرط داریم که دو به دو ناسازگارند و به ترتیب با C1 تا Cn نشان داده می‌شوند و هر کدام باعث انجام یک کار بخصوص به نام Si می‌شوند. اگر P(Ci) احتمال این باشد که Ci مقدار True داشته باشد و برای i < j داشته باشیم P(Ci) >= P(Cj)، در این صورت موثرترین و کارآمدترین ساختار if به شکل زیر خواهد بود:

IF C1 THEN
S1
ELSE IF C2 THEN
S2
ELSE IF ....
ELSE IF C(n-1) THEN
S(n-1)
ELSE
Sn

تحقق یک شرط و اجرای statement مربوط به آن باعث کامل شدن if statement می‌شود و بنابراین باقی تست‌ها دور زده می‌شوند.

🔴 اگر متغیر Found از نوع Boolean باشد، کد سخت‌خوان زیر را خیلی ساده می‌توان به صورت دیگری نوشت:

IF Key = ValueSought THEN
Found := True
ELSE
Found := False

{---------------------------------------------------}

Found := Key = ValueSought;         { ✅ }

برنامه‌ای که در مثال 4.9 می‌بینید ارقام عربی را به وسیله‌ی تقلیل متوالی که به صورت غربال پیاده‌سازی شده است به اعداد رومی تبدیل می‌کند. این عملیات تقلیل را با if statement ها انجام داده‌ایم.   ⬅ مثال 4.9

case statement

case statement از یک expression که به آن selector می‌گوییم، و یک لیست از statement ها تشکیل شده است. هر عنصر در این لیست statement ها به یک (یا بیشتر) مقدار ثابت که از نوع selector است مرتبط می‌شود. selector باید از نوع ordinal باشد. هر constant value باید حداکثر به یک statement متصل شده باشد. این ساختار statement ای را جهت اجرا انتخاب می‌کند که به مقدار فعلی selector متصل شده است؛ اگر چنین constant ای در لیست نباشد خطا رخ می‌دهد. بعد از اتمام statement انتخاب شده، کنترل به پایان case statement می‌رود. سینتکس دیاگرام case statement به صورت زیر است:

مثال

🔴 case statement ها لیبل نیستند و نمی‌توان با یک goto statement به آن‌ها پرش کرد. ترتیب آن‌ها دلخواه است و اهمیتی ندارد.

🔴 اگرچه کارایی case statement به نوع پیاده‌سازی‌اش بستگی دارد، ولی قاعده‌ی کلی این است که وقتی چندین statement داریم که دو به دو ناسازگارند، یا به عبارتی mutual exclusive هستند، و احتمال انتخابشان یکسان است، از case statement استفاده می‌کنیم.

⛔ پاسکال استاندارد در case statement چیزی مانند default در ساختار switch زبان C ندارد. اگر selector مقداری داشته باشد که برنامه‌نویس آن را در یک constant value پیش‌بینی نکرده باشد، برنامه خطای زمان اجرا run time می‌دهد. Free Pascal کلمه‌ی کلیدی ELSE و OTHERWISE را فراهم کرده است که هر دو نقشی مانند default در ساختار switch زبان C دارند. بعد از ELSE و یا OTHERWISE ; نمی‌آید. علاوه بر این حتی اگر ELSE و OTHERWISE وجود نداشته باشند، Free Pascal در صورت برابر نبودن selector با یک constant value معرفی شده توسط برنامه‌نویس، بدون خطا از case statement خارج می‌شود.

  ⬅ این مثال را با P4 و Free Pascal کامپایل و اجرا کنید تا تفاوت را متوجه شوید.

with statement

with statement در همراهی با متغیرهایی که از نوع RECORD هستند استفاده می‌شود. در فصل ۷ در این مورد صحبت خواهیم کرد.

goto statement

goto statement بیان می‌کند که کنترل اجرا باید به جای دیگری از برنامه، یعنی label ای که نامش در ادامه‌ی GOTO آمده است، منتقل شود.

هر label:

  1. قبل از ظاهر شدن در block باید در label declaration part اعلان شده باشد.
  2. باید فقط و فقط در ابتدای یک statement در block statement part بیاید.
  3. scope اش شامل تمام text آن block می‌شود مگر در بلاک‌های تو در تو که آن label را مجددا اعلان کرده‌اند.

حداقل یکی از ۳ شرط زیر برای label ها و goto statement هایی که به آن‌ها ارجاع می‌دهند برقرار باشد:

  1. The label prefixes a statement which contains the goto statement.
  2. The label prefixes a statement in a statement sequence (within a compound statement or repeat statement) and any statement in the statement sequence contains the goto statement.
  3. The label prefixes a statement in the statement sequence forming the statement part of a block that contains a procedure or function that contains the goto.

💡 مورد ۲ می‌گوید که اگر label و GOTO در داخل یک statement sequence باشند کاملا درست است و نکته‌ی سوم بیان می‌دارد که پرش از بلاک داخلی به بلاک خارجی صحیح است. (کلمه‌ی بلاک را با اغماض خیلی زیاد به کار بردم.)
  ⬅ مثال
  ⬅ مثال

🔔 موارد فوق را شاید بتوان به این صورت راحت‌تر به خاطر سپرد:

1. Label در scope یا حوزه‌ی دید دستور goto باشد.
2. حتی اگر label در scope باشد، هرگز اجازه‌ی پرش به یک block داخلی (procedure یا function) را نداریم. بدیهی است که از نظر معنایی پرش به یک زیرروال بدون اینکه مقدمات فراخوانی آن، مثلا تشکیل stack، فراهم شده باشد، غیرقابل درک است!
3. اجازه‌ی پرش از بیرون یک structured statement به درون آن را نداریم.
4. پرش از یک block یا structured statement داخلی به یک block یا structured statement بیرونی مجاز است.

🔴 قطعه کد زیر را ببینید و کامنت‌ها را بخوانید:

LABEL
    1;              { block A }
    ...
    PROCEDURE B;    { block B }
        LABEL
            3, 5;
    BEGIN
        GOTO 3;
    3:  WriteLn('Hello');
    5:  IF P THEN
        BEGIN
            S;
            GOTO 5
        END;        { WHILE P DO S }
        GOTO 1;     { this causes early termination of the activation of B }
        WriteLn('Goodbye');     { unreachable statement }
    END;            { block B }

BEGIN
    B;
1:  WriteLn(' Edsger')
    { a "GOTO 3" is not allowed in block A }
END { block A }

🔴 اجازه‌ی jump از بیرون یک structured statement به درون آن را نداریم. از این رو مثال‌های زیر همگی نادرست هستند:

{------------------------------------}
FOR I := 1 TO 10 DO
BEGIN
    S1;
3:  S2;
END;
GOTO 3
{------------------------------------}
IF B THEN GOTO 3;
    ...
IF B1 THEN
3:  S
{-------------------------------------}
PROCEDURE P;
    PROCEDURE Q;
    BEGIN
        ...
    3:  S
    END;
BEGIN
    ...
    GOTO 3      { Label 3 is not accessible from outer block }
END.

goto statement مختص موقعیت‌های غیرطبیعی و غیرمعمولی است که در آن‌ها نمی‌توان ساختار طبیعی یک الگوریتم را به صورت منطقی با structured statement ها بیان کرد. یک وضعیت معمول هندل کردن یک داده‌ی ورودی است که نوعی غیر از نوع مورد انتظار ما دارد:

Read(c);
IF NOT (C IN ['0'..'9']) THEN
    GOTO InvalidInput;

مثال

یک قاعده‌ی خوب این است که از استفاده از jump ها برای بیان iteration های معمولی و اجراهای conditional مجموعه statement ها استفاده نکنیم؛ زیرا چنین پرش‌هایی بازتاب یا reflection ساختار محاسبه را در ساختار متنی استاتیک برنامه از بین می‌برند.

علاوه بر موارد فوق، عدم تناظر بین متن برنامه و ساختار محاسباتی آن (static و dynamic)، برای وضوح و شفافیت برنامه به شدت زیان آور است و کارِ اثباتِ درستیِ برنامه را بسیار مشکل‌تر می‌کند. وجود GOTO در یک برنامه‌ی پاسکال اغلب نشانه‌ی این است که برنامه‌نویس هنوز یاد نگرفته است که «به سبک پاسکال فکر کند» (چون GOTO در بعضی زبان‌های برنامه‌نویسی دیگر یک سازه‌ی ضروری است).

نکات متفرقه

دسته‌بندی statement ها

پاسکال در مجموع یازده statement دارد که در دو دسته‌ی simple statement و structured statement طبقه‌بندی می‌شوند:

statement
│
├── simple statement
│   ├── assignment
│   ├── procedure
│   ├── goto
│   └── empty
│
└── structured statement
    ├── compound
    ├── if
    ├── case
    ├── while
    ├── repeat
    ├── for
    └── with

💡 اینکه پروسیجرها در لیست statement های ساده قرار دارند شما را در مورد function به اشتباه نیندازد. توابع چون مقدار برمی‌گردانند در لیست expression ها قرار می‌گیرند.

statement sequence

statement sequence توالی از statement ها است که با ; از هم جدا شده‌اند. در پاسکال statement sequence ها فقط در compound statement ها و repeat statement وجود دارد. این دو خودشان یک statement هستند ولی بدنه‌شان statement sequence است.

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