در مورد الگوریتم ماشین حساب ما استفاده از یک بافر برای گرفتن عبارت بطور کامل و سپس تجزیه کردن اجزای (Parse) آن از لحاظ فنی غیر ممکن نیست و تنها بدلیل صورت مسئله قادر به انجام آن نیستیم.
اما تصور کنید که اگر قرار بود مرورگرهای وب (Web Browsers) ابتدا تمام محتوای یک صفحه را بخواندند و سپس آن را تجزیه کرده و نمایش دهند چه مقدار زمان کاربر و سرویس دهنده وب به هدر میرفت و ترافیک بیهودهای برروی خطوط ارتباطی حاصل میشد (در اکثر موارد ما با دیدن تنها چند خط از یک صفحه به صفحه دیگری میرویم(.
مقدمه
یک الگوریتم مجوعهی متناهی از دستورالعمل های خوش تعریف برای انجام یک عمل است که با داشتن یک حالت اولیه به حالت پایانی مشخص و متناظری خواهد رسید.
(با استدلالی ( heuristic )مقایسه شود(
مفهوم یک الگوریتم معمولاً با مثال دستور اشپزی توضیح داده می شود.
هر چند بعضی الگوریتم ها خیلی پیچیده تر هستند.
الگوریتم ها معمولاً دارای مراحلی است که تکرار می شود تکرار و یا تا زمان پایان برنامه نیازمند decision هایی (مانند منطق بولی یا نابرابری است.
اگر الگوریتم مناسب و نا معیوب نباشد حتی با اجرای درست آن هم مسئله حل نمی شود.
برای مثال اجرای الگوریتم سالاد سیب زمینی در صورتی که سیب زمینی در کار نباشد حتی اگر تمام حرکات تهیه سالاد طوری انجام شود مثل اینکه سیب زمینی وجود دارد نا فرجام خواهد ماند.الگوریتم های مختلف ممکن است یک عمل را با دستورات مختلف در مدت زمان، جا، وبا تلاش کمتر یا بیشتری نسبت به بقیه انجام دهد.
برای مثال با داشتن دو دستور تهیه ی سالاد سیب زمینی، یکی ممکن است قبل از جوشاندن اول سیب زمینی را پوست بکند در حالی که دیگری این دو مرحله را برعکس انجام دهد، و هر دو این مراحل را برای تمام سیب زمینی ها تکرار می کنند تا وقتی که سالاد سیب زمینی آماده طبخ شود.(مثال ضعیف...
چه کسی سیب زمینی ها را جدا جدا می جوشاند؟
و معمولاً تهیه ی سالاد نیازی به پخت و پز ندارد...(
در بعضی کشورها، مثل امریکا، اگر تعبیه فیزیکی الگوریتم ها ممکن باشد ممکن است آن ها به شدت انحصاری شود (برای مثال، یک الگوریتم ضرب ممکن است در واحد محاسبه ی یک ریز پردازنده تعبیه شود (
________________________________________
الگوریتم های رسمی شده(formalized algorithms )
الگوریتم ها به خاطر روش پردازش اطلاعات توسط کامپیوتر اساسی و حیاتی هستند، چون یک برنامه کامپیوتری اساساً یک الگوریتم است که به کامپیوتر می گوید برای انجام یک عمل خاص مثل محاسبه حقوق کارمندان و یا چاپ ورقه گزارش دانش آموزان،چه مراحل خاصی را (با چه نظم خاصی) اجرا کند،.به این صورت، یک الگوریتم را می توان هر دنباله از دستوراتی که قابل اجرا توسط یک Turing complete باشد به حساب آورد.به طور نمونه ای هنگامی که الگوریتم کار پرازش اطلاعات را انجام می دهد، داده از طریق یک وسیله یا منبع ورودی گرفته، به یک وسیله خروجی یاsink نوشته و / یا برای استفاده در زمانی دیگر ذخیره می شود.
داده ذخیره شده به عنوان بخشی از حالت درونی(internal state) نهاد مجری الگوریتم تلقی می گردد.برای اعمال محاسباتی از این قبیل، الگوریتم باید به دقت تعریف شود :یعنی طوری مشخص شود که برای حالت مختلف محتمل معتبر باشد.
یعنی تمام مراحل شرطی باید به طور سیستماتیک بررسی شود ; حالت به حالت.ضابطه مربوط به هر حالت باید واضح (و محاسبه پذیر باشد(.چون الگوریتم ها لیست دقیقی از گام های دقیق است، نظم محاسبه تقریباً همیشه برای کار کرد الگوریتم اساسی می باشد.
همواره فرض می شود دستور ها روشن هستند، و گفته می شود از" بالا آغاز" و"تا پایین کشیده می شوند"، اندیشه ای که به طور رسمی تر توسط جریان کنترل توصیف می شود.تا اینجا ی بحث، رسمی سازی قواعد و قوانین برنامه نویسی امری(imperative programming) را به خود گرفت.
این عام ترین مفهوم است، و تلاش دارد با وسایل "مکانیکی" مجزا کاری را توصیف کند؛ عملیات تخصیص، تعیین مقدار یک متغیر، برای این مفهوم از الگوریتم رسمی شده یکتا می باشد .در زیر مثالی از این تخصیص آمده است.برای مفاهیم فرعی ) (alternative تشکیل دهنده یک الگوریتم برنامه نویسی تابعی و برنامه نویسی منطقی را ببینید.
ماشین حساب (آشنایی با Syntax Diagram(
ماشین حساب (آشنایی با Syntax Diagram( الگوریتم ماشین حسابی با تعریف زیر را بنویسید: انجام چهار عمل اصلی با اولویت محاسباتی عملگرها طبق آنچه در زیر مشخص شده است: کد: + - عملگر یگانی (Unary) * / + - عملگر دودویی (Binary) عبارات داخل پرانتز از اولویت بالاتری برخوردارند.
اعداد میتوانند صحیح یا اعشاری باشند.
پایان هر عبارت با علامت سوال (=) مشخص میشود.
خروج از ماشین حساب با ورود حرف ایکس (X) مشخص میشود.
مثال: کد: 2 * 3 + 4 * 5 = 26 2 * (3 + 4) * 5 = 70 2 * 3 + -4 * 5 = -14 8.1 / -2.5 = -3.24 X شرایط الگوریتم: برای گرفتن عبارت مورد محاسبه از کاربر٬ تنها یک تابع به نام GetChar وجود دارد که در هر زمان تنها یک کاراکتر از کاربر گرفته و آن را برمیگرداند.
به جز آخرین کاراکتر وارد شده توسط کاربر٬ الگوریتم نباید کاراکترهای قبلی وارد شده توسط کاربر را در متغیری ذخیره کند.
الگوریتم ارائه شده باید بر روی هر ماشین٬ سیستم عامل و زبان برنامهنویسی قابل پیادهسازی باشد.
برنامه نویسی تابعی برنامهنویسی تابعی یک دسته بندی برنامه نویسی است که با محاسبه به عنوان یک ارزیابی از تابعهای ریاضی رفتار میکند.
در مقایسه با برنامه نویسی آمرانه، برنامهنویسی تابعی روی ارزیابی عبارات تابعی نسبت به اجرای فرامین تاکید بیشتری دارد.
عبارات در این زبان با استفاده از توابع به منظور ترکیب مقادیر پایه ای شکل میگیرند.
توابع ریاضی استحکام زیادی از لحاظ تحلیل و تطابق دارند.
به عنوان مثال، اگر یک تابع idempotent شناخته شده باشد، یک فراخوانی تابع که خودش را به عنوان آرگومان میگیرد، و هیچ اثرات جانبی ندارد، ممکن است به صورت کارآمدی بدون فراخوانیهای چندگانه محاسبه شود.
یک تابع از این جهت، صفر یا تعداد بیشتری پارامتر ورودی، و یک مقدار بازگشتی دارد.
پارامترها ( یا آرگومانها، که گاهی به این نام خوانده میشوند) ورودیهای تابع هستند، و مقدار بازگشتی، خروجی تابع است.
تعریف تابع تشریح میکند که تابع چگونه باید برحسب توابع دیگر ارزیابی شود.
به عنوان مثال، تابع"" برحسب توابع توان و جمع تعریف شده است.
از بعضی دیدگاهها، زبان باید توابع اساسی را داشته باشد تا نیاز به تعریف بیشتر نباشد.
توابع میتوانند از راههای گوناگونی در یک زبان برنامهنویسی تابعی دستکاری شوند.
با توابع به عنوان مقدارهای کلاس اول رفتار میشود، که باید گفته شود توابع میتوانند پارامترها یا ورودیهای توابع دیگر بوده ونیز مقادیر بازگشتی یا خروجیهای یک تابع باشند.
این به توابعی مثل mapcar در LISP و map در Haskell اجازه میدهد که هم یک تابع و هم یک لیست را به عنوان ورودی بردارند و تابع ورودی را برای هر عنصر از لیست بکار برند.
توابع میتوانند نامگذاری شوند، مانند زبانهای دیگر، یا به صورت بینام ( گاهی در حین اجرای برنامه) با استفاده از انتزاع lambda تعریف شده و به عنوان مقدار در توابع دیگر استفاده شوند.
زبانهای تابعی همچنین به توابع، امکان "پرداخت" شدن را میدهد.
پرداخت یک تکنیک برای دوبارهنویسی یک تابع با پارامترهای چندگانه به عنوان ترکیبی از توابع یک پارامتر است.
یک تابع پرداخت شده می تواند برای یک زیر مجموعه از پارامترهایش به کار رود.
نتیجه تابعی است جایی که پارامترها در این زیر مجموعه حالا به عنوان ثابت ها، ثابت شده اند و مقادیر بقیه ی پارامترها هنوز نامشخص است.
این تابع جدید می تواند برای پارامترهای باقی مانده برای بدست آوردن مقدار تابع نهایی بکار رود.
به عنوان مثال، یک تابع میتواند پرداخت شود بنابراین مقدار بازگشتی (توجه داشته باشید که پارامتر y وجود ندارد) یک تابع بینام خواهد بود که معادل تابع است.
این تابع جدید فقط یک پارامتر دارد و معادل جمع 2 با یک عدد است.
دوباره تاکید میکنیم که چنین چیزی تنها به این دلیل ممکن است که با توابع به عنوان مقادیر کلاس اول رفتار میشود.
حساب Lambda میتواند اولین زبان برنامهنویسی تابعی در نظر گرفته شود، اگر چه برای اجرا روی یک کامپیوتر طراحی نشده است.
حساب Lambda یک مدل محاسبه است که به وسیلهی Alonzo Church در دههی 1930 طراحی شده است که یک راه خیلی رسمی برای توصیف ارزیابی تابع تامین می کند.
اولین زبان برنامهنویسی تابعی بر اساس کامپیوتر زبان پردازش اطلاعات (IPL) بود، که بوسیلهی Newell، Shaw، و Simon در شرکت RAND برای کامپیوتر JOHNNIAC در اواسط دههی 1950 گسترش یافت.
زبان برنامهنویسی تابعی پیشرفتهتر LISP بود که به وسیلهی جان مک کارتی در انستیتوی تکنولوژی ماساچوست برای کامپیوترهای علمی IBMسری 700/7000 در اواخر دههی1950 گسترش یافت.
در حالیکه LISP یک زبان برنامه نویسی تابعی کامل نبود، ولی بسیاری از خصیصه هایی را که الان در زبانهای برنامهنویسی تابعی مدرن یافت میشود را معرفی میکرد.
زبان Scheme تلاش بعدی برای ساده سازی و گسترش LISP بود.
در دههی 1970 زبان ML در دانشگاه ادینبرگ ایجاد شد، و دیوید ترنر زبان Muranda را در دانشگاه کنت گسترش داد.
زبان Haskell در اواخر دههی 1980 در یک تلاش برای جمع آوری نظرات در تحقیق برنامه نویسی تابعی ایجاد شد.
مقایسه با برنامهنویسی آمرانه برنامهنویسی تابعی میتواند با برنامه نویسی آمرانه مقایسه شود.
برنامهنویسی تابعی به نظر می رسد ساختارهای مختلفی را که برای یک زبان آمرانه ضروری است مثل C یا پاسکال از دست میدهد.
به عنوان مثال، در برنامهنویسی تابعی دقیق، هیچ تخصیص حافظهی صریح و هیچ تخصیص متغیر صریحی وجود ندارد.
اگرچه، این عملیات وقتی تابعی احضار میشود به صورت اتوماتیک اتفاق میافتد.
تخصیص حافظه برای ایجاد فضا برای پارامترها و مقدار بازگشتی انجام می شود و تخصیص برای کپی پارامترها به این فضای اختصاص یافتهی جدید و کپی مقدار بازگشتی به تابع فراخوانی شده اتفاق میافتد.
هر دو عملیات میتوانند فقط روی خروج و ورود تابع اجرا شوند، بنابراین اثرات جانبی ارزیابی تابع حذف میشود.
با رد کردن اثرات جانبی در توابع، زبان شفافیت ارجاعی پیدا میکند.
این سبب میشود که نتیجه ی یک تابع برای یک مجموعهی مشخص از پارامترها یکسان شود بدون اهمیت به اینکه کی و کجا ارزیابی شده است.
شفافیت ارجاعی به میزان زیادی وظیفه ی اثبات صحت برنامه و وظیفه ی شناسایی اتوماتیک محاسبات مستقل برای اجرای موازی را آسان میکند.
حلقه، دیگر ساختار برنامهنویسی آمرانه، در طول ساختار تابعی عمومی تر بازگشت انجام می شود.
توابع بازگشتی خودشان را احضار می کنند، و به یک عمل اجازهی اجرای مکرر را میدهند.
در حقیقت، میتوان ثابت کرد که حلقه معادل نوع خاصی از بازگشت است که بازگشت دنبالهای نامیده میشود.
بازگشت در برنامهنویسی تابعی می تواند شکلهای گوناگونی بگیرد و عموماً یک تکنیک قویتری نسبت به حلقه است.
به همین دلیل، تقریباً همهی زبانهای آمرانه نیز آن را پشتیبانی میکنند (بجز زبانهایی مثل FORTRAN 77 و COBOL).
زبانهای برنامهنویسی تابعی برنامههای تابعی "خالص" نیاز به هیچ متغیر و اثرات جانبی ندارد، و بنابراین به صورت اتوماتیک امنیت رشتهای ، قابلیت تغییر اتوماتیک ( تا زمانی که هر سیکل بازگشتی عاقبت بایستد) و بسیاری ماهیتهای خوب از این نوع دارند.
توابع تودرتو فقط نتایج شان را به تابع اصلی باز میگردانند.
تکمیل این زبانها معمولاً استفادهی کاملاً ماهرانهای از دستکاری stack را ممکن میسازد، همان طوری که معمولاً نیز استفاده میشود.
برنامهنویسی تابعی اغلب بستگی زیادی به بازگشت دارد.زبان برنامه نویسی Scheme حتی نیاز به انواع مشخص بازگشت بازگشت دنبالهای دارد که شناخته شود و به صورت اتوماتیک به وسیله کامپایلر بهینه شود.
درضمن، زبانهای برنامهنویسی تابعی احتمال دارد شفافیت مرجعی را اجرا کند، تصور آشنایی است که مساویها میتوانند با یکدیگر جایگزین شوند: اگر دو عبارت با مقدارهای مساوی تعریف شوند، یکی میتواند درهر عبارت بزرگتری، بدون تاثیر روی نتیجهی محاسبه جایگزین دیگری شود.
به عنوان مثال، در ما میتوانیم sqrt (2) را فاکتور بگیریم و بنویسیم بنابراین ارزیابی اضافی از تابع ریشهی دوم حذف میشود.
بدیهی است که چنین موردی همیشه در زبان آمرانه برقرار نیست.
یک مورد مناسب، تابع getchar ( ) زبان برنامه نویسی C است، که اکیداً تابعی است نه از آرگومانهایش که از محتوای جریان ورودی stdin و مقداری که قبلاً خوانده شده است.
به مثال روبرو توجه کنید: ما نمیتوانیم getchar ( ) را مانند sqrt (2) حذف کنیم، چون در C، " getchar ( )" باید دو مقدار متفاوت را در دو باری که فراخوانی میشود برگرداند.
اثرات جانبی مخفی، عموماً یک قانون از زبانهای برنامهنویسی قدیمی است، تا استثناء،.
هر بار یک رویه یک مقدار را میخواند یا یک مقدار را در یک متغیر global یا اشتراکی مینویسد، پتانسیل اثرات جانبی مخفی وجود دارد.
این نشر اطلاعات در طول مرزهای رویه به طریقی که صریحاً با تعاریف و فراخوانیهای تابع نشان داده نمیشود شدیداً پیچیدگی مخفی برنامههای نوشته شده در زبانهای غیر تابعی قراردادی را افزایش میدهد.
با حذف این شکافهای اطلاعاتی مخفی، زبانهای برنامهنویسی تابعی امکان برنامههای بهتر که برای طراحی و عیبیابی، سادهترند را فراهم میکند.
اگر چه، آنها محاسن دیگری نیز دارند.
بیشتر برنامهنویسان به دستهبندی آمرانه عادت کردهاند و یادگیری برنامهنویسی تابعی، که شامل کل راههای مختلف ترکیب برنامهها میباشد را سخت میدانند.
این مشکل همراه با این حقیقت که محیطهای برنامهنویسی تابعی، کتابخانه و وسایل جامع در دسترس برای زبانهای برنامهنویسی قدیمی را ندارند، از مهمترین دلایلی است که برنامهنویسی تابعی استفادهی کمی در صنعت نرمافزار پیدا کرده است.
زبانهای تابعی در حوزهی دانشگاهی و سرگرمی باقی ماندهاند، تاخت و تاز کمی که صورت گرفته در نتیجهی زبانهای تابعی ناخالص مانند Erlang و Common Lisp است.
میتوان چنین بحث کرد که بیشترین تاثیر برنامهنویسی تابعی روی صنعت نرمافزار به وسیلهی برنامهنویسان با تحصیلات دانشگاهی انجام شده که کاربرد مدل برنامهنویسی تابعی ناخالص را در کارهایشان در زبانهای آمرانه قدیمی ادامه دادند.
توابع مرتبه بالاتر یک مکانیزم قدرتمند که گاهی اوقات در برنامهنویسی تابعی استفاده میشود عقیدهی توابع مرتبه بالاتر است.
توابع مرتبه بالاتر، توابعی هستند که بتوانند توابع دیگر را به عنوان آرگومان قبول کنند و یا آنها را به عنوان نتیجه برگردانند، کلمه مشتق در حساب یک نمونهی معمول از یک تابعی است که تابعی را به تابع دیگر تصویر میکند.) توابع مرتبه بالاتر درتئوری حساب Lambda قبل از این که تصور برنامهنویسی تابعی به وجود بیاید، مطالعه شده بودند، و روی طراحی بسیاری از زبانهای برنامهنویسی تابعی، مانند Haskell تاثیر گذاشته اند، و حتی بذر دستهبندی برنامه نویسی سطح تابع را که شامل زبانهایی مثل Backus'FP است را افشاندند.
ملاحظات فضا و سرعت زبانهای تابعی به عنوان گرسنهی منبع مورد انتقاد قرار گرفتهاند، هم برحسب حافظه و هم منابع CPU.
این در اصل نتیجه دو چیز است: زبانهای تابعی اولیه بدون هیچ تلاشی در بازدهی تکمیل شده بودند.
زبانهای غیر تابعی با ترک کردن خصیصههایی مثل چک مرزها یا جمعآوری زباله که به عنوان بخش ضروری چارچوبهای کاری محاسبات مدرن، سربار چیزی که به وسیله ی پیش فرض جزئی از ساختمان زبانهای تابعی بود، به نظر می رسد حداقل تا یک اندازه سرعت بدست میآورند.
وقتی زبانهای آمرانهی مدرن و تکمیلات آنها شروع به در برگرفتن تاکید بیشتر روی صحت نسبت به سرعت خام کردند و تکمیلات زبانهای تابعی شروع به تاکید روی سرعت به اندازهی صحت کرد، اجرای زبانهای تابعی و زبانهای آمرانه شروع به همگرایی کرد.
برای زبانهایی که بیشتر وقتشان را روی انجام محاسبات عددی میگذرانند، بعضی از زبانهای تابعی (مثل OCmal و Clean ) میتوانند به سرعت C نزدیک شوند، در حالی که برای برنامههایی که ماتریسهای بزرگ و بانکهای اطلاعاتی چند بعدی را دستکاری میکنند، زبانهای تابعی آرایهای (مثل J و K) معمولاً سریعتر از برنامههای C غیر بهینه هستند.
اگرچه، زبانهای تابعی خالص میتوانند به صورت قابل ملاحظهای هنگام دستکاری ساختارهای اطلاعاتی بزرگ در نتیجهی استفادهی حافظهی کمتر کارآمد، کند شود.
ارزیابی تنبل نیز یک سربار اضافی در زبانهایی مثل Haskell اضافه میکند.
در مورد ماشین حساب ورودی ما تنها یک عبارت ریاضی است که زیاد هم بزرگ نخواهد بود٬ اما متنی که توسط یک کامپایلر تجزیه تحلیل میشود میتواند به چندین میلیون خط هم برسد.
در این حالت اگر کامپایلر نیاز داشت که تمام خطوط را در حافظه قرار دهد به چه میزان حافظه نیاز داشت تا تنها به این نکته پی ببرد که آیا خطایی در متن برنامه وجود دارد یا نه؟
در مواردی که ورودی ما از الگوی خاصی (Syntax) تبعیت میکند٬ به منظور یافتن الگوریتم مناسب برای تجزیه اجزا (Parse) و تفسیر معنای (Semantics) هر جزء از Syntax Diagram استفاده میشود.
همانند فلوچارت که میتواند برای نوشتن یک الگوریتم بکار رود٬ Syntax Diagram هم روشی دیگر برای نوشتن یک الگوریتم است.
حال به یافتن الگوریتم ماشین حساب میپردازیم تا در این مثال به چگونگی استفاده از Syntax Diagram آشنا شوید.
برای ساده کردن عبارات از دوران ابتدایی آموختهایم که: هر عبارت داخل پرانتز خود میتواند به عنوان عبارتی مستقل محاسبه شده و در نهایت بصورت یک عدد در عبارت اولیه جایگزین شود.
علامتهای مثبت و منفی همواره پیش از یک عدد یا یک پرانتز قرار دارند (عملگرهای یگانی( حاصل ضرب و تقسیم تمام اعدادی که با عملگرهای ضرب و تقسیم به هم مرتبط هستند بدون نیاز به اولویتبندی قابل محاسبه بوده و حاصل میتواند در عبارت اولیه جایگزین گردد (عملگرهای ضرب و تقسیم( حاصل جمع و تفریق تمام اعدادی که مابین عملگرهای جمع و تفریق قرار دارند بدون نیاز به اولویتبندی قابل محاسبه هستند و حاصل میتواند در عبارت اولیه جایگزین گردد (عملگرهای جمع و تفریق دودویی( با این معلومات و با شروع از کلیات تا رسیدن به جزئیات (Top-Down Design) اقدام به طراحی الگوریتم میکنیم.
ماشین حساب: ورودی میتواند حرف X باشد که در این صورت خارج میشویم یا یک عبارت و به دنبال آن علامت تساوی (=) که در این صورت دوباره از اول کار شروع میکنیم.
عبارت: یک عبارت تشکیل شده است از یک جمله یا حاصل جمع یا تفریق دو یا چند جمله.
جمله: یک جمله تشکیل شده است از یک ضریب یا حاصل ضرب یا تقسیم دو یا چند ضریب.
ضریب: یک ضریب میتواند در ابتدا یکی از علامتهای مثبت یا منفی باشد و سپس، یا یک عدد یا یک عبارت داخل پرانتز (عبارت تعریفی است بازگشتی).
عدد: یک عدد تشکیل شده است از یک نقطه (.) و سپس یک یا چند رقم، یا تنها یک یا چند رقم٬ یا یک یا چند رقم و سپس یک نقطه (.) و پس از آن یک یا چند رقم.
رقم: یک رقم یکی از حروف 0 تا 9 است.
خوب الگوریتم ما به همین سادگی نوشته شد.
در هر مرحله٬ هرگاه ورودی با آنچه که در Syntax Diagram مربوطه انتظارش را داریم نخواند به معنی این است که عبارت مورد محاسبه نادرست وارد شده است.در بالا برای ساده کردن Syntax Diagram ها فاصلهها را ندید گرفتهام ولی همانجور که پیداست به غیر از داخل یک عدد٬ در بقیه موارد لازم است که فاصلهها را ندید بگیریم.
برای ایم منظور با استفاده از تابع GetChar که در صورت مسئله عنوان شده است٬ تابع دیگری مینویسیم که در آن بر حسب پارامتر تابع بتوانیم فاصلهها را رد کنیم.
جدا از آن این تابع آخرین حرف خوانده شده را در داخل یک متغیر که توسط همه توابع قابل دسترسی است ذخیره میکند.
کد: var C: Char; const BlankChars = [' ', #9, #10, #13]; procedure FetchNextChar(SkipBlanks: Boolean); begin repeat C := GetChar; until not (SkipBlanks and (C in BlankChars)); end; و بدنبال توابع مربوط به هر Syntax Diagram نوشته شده است.
هر تابع در صورت برخورد با خطا مقدار False را برمیگرداند٬ والا مقدار برگشتی True است.
ماشین حساب: کد: procedure Calculator; var Value: Double; begin Writeln('Enter an expression or X to exit:'); FetchNextChar(True); while C <> 'X' do begin if GetExpression(Value) and (C = '=') then Writeln(Value) else begin Writeln('Illegal expression!'); while C <> '=' do { ignores the rest of the illegal expression } FetchNextChar(True); end; Writeln; Writeln('Enter an expression or X to exit:'); FetchNextChar(True); end; end; عبارت: کد: function GetExpression(var Expr: Double): Boolean; var NextTerm: Double; Op: Char; begin Result := False; if GetTerm(Expr) then begin Result := True; while Result and (C in ['+', '-']) do begin Op := C; FetchNextChar(True); Result := False; if GetTerm(NextTerm) then begin case Op of '+': Expr := Expr + NextTerm; '-': Expr := Expr - NextTerm; end; Result := True; end; end; end; end; جمله: کد: function GetTerm(var Term: Double): Boolean; var NextFactor: Double; Op: Char; begin Result := False; if GetFactor(Term) then begin Result := True; while Result and (C in ['*', '/']) do begin Op := C; FetchNextChar(True); Result := False; if GetFactor(NextFactor) then begin if Op = '*' then begin Term := Term * NextFactor; Result := True; end else if NextFactor <> 0 then begin Term := Term / NextFactor; Result := True; end; end; end; end; end; ضریب: کد: function GetFactor(var Factor: Double): Boolean; var Negate: Boolean; begin Result := False; Negate := False; if C in ['+', '-'] then begin if C = '-' then Negate := True; FetchNextChar(True); end; if C = '(' then begin FetchNextChar(True); if GetExpression(Factor) and (C = ')') then begin FetchNextChar(True); Result := True; end; end else if GetNumber(Factor) then Result := True; if Negate then Factor := -Factor; end; عدد: کد: function GetNumber(var Number: Double): Boolean; var Digit: Integer; Fraction: Double; PointPos, P: Integer; begin Result := False; Number := 0; while GetDigit(Digit) do begin Number := Number * 10 + Digit; FetchNextChar(False); Result := True; end; if C = '.' then begin FetchNextChar(False); PointPos := 0; while GetDigit(Digit) do begin Fraction := Digit; Inc(PointPos); for P := 1 to PointPos do Fraction := Fraction / 10; Number := Number + Fraction; FetchNextChar(False); Result := True; end; end; if C in BlankChars then FetchNextChar(True); end; رقم: کد: function GetDigit(var Digit: Integer): Boolean; begin Result := False; if C in ['0'..'9'] then begin Digit := Ord(C) - Ord('0'); Result := True; end; end; برای تمرین سعی کنید با استفاده از Syntax Diagram عملگری برای به توان رساندن و چند تابع ریاضی (مثل Sin و Cos و ...) به ماشین حساب اضافه کنید.