bc(1) General Commands Manual bc(1)

bc - زبان پردازش عددی و ماشینحساب با دقت دلخواه

bc [ -hlwsqv ] [long-options] [ file ... ]

دستور bc زبانی است که از اعداد با دقت دلخواه همراه با اجرای تعاملی دستورات پشتیبانی می‌کند. شباهت‌هایی میان نحو (سینتکس) این زبان و زبان برنامه‌نویسی C وجود دارد. یک کتابخانه ریاضی استاندارد از طریق گزینه خط فرمان در دسترس است. در صورت درخواست، این کتابخانه ریاضی پیش از پردازش هرگونه پرونده تعریف می‌شود. bc کار خود را با پردازش کد از تمام پرونده‌های فهرست‌شده در خط فرمان، به همان ترتیب ذکر شده آغاز می‌کند. پس از پردازش تمامی پرونده‌ها، bc از ورودی استاندارد می‌خواند. تمام کدها به محض خوانده شدن اجرا می‌شوند. (اگر پرونده‌ای شامل دستوری برای متوقف کردن پردازنده باشد، bc هرگز از ورودی استاندارد نخواهد خواند.)

این نسخه از bc شامل چندین قابلیت افزوده فراتر از پیاده‌سازی‌های سنتی bc و پیش‌نویس استاندارد POSIX است. گزینه‌های خط فرمان می‌توانند سبب شوند که این افزونه‌ها هشدار چاپ کنند یا رد شوند. این سند زبانی را که توسط این پردازنده پذیرفته می‌شود شرح می‌دهد. افزونه‌ها به همین عنوان مشخص خواهند شد.

چاپ راهنمای استفاده و خروج.
اجبار به حالت تعاملی.
تعریف کتابخانه ریاضی استاندارد.
نمایش هشدارها برای افزونه‌های فراتر از POSIX bc.
پردازش دقیق زبان استاندارد POSIX bc.
عدم چاپ پیام خوش‌آمدگویی معمول GNU bc.
چاپ شماره نسخه و حق نشر و خروج.

بنیادی‌ترین عنصر در bc عدد است. اعداد، اعدادی با دقت دلخواه هستند. این دقت هم در بخش صحیح و هم در بخش اعشاری وجود دارد. تمامی اعداد در داخل به صورت ده‌دهی نمایش داده می‌شوند و کلیه محاسبات در مبنای ده‌دهی انجام می‌گیرد. (این نسخه نتایج حاصل از عملیات ضرب و تقسیم را کوتاه/قطع می‌کند.) اعداد دارای دو مشخصه هستند: طول (length) و مقیاس اعشار (scale). طول، تعداد کل ارقام ده‌دهی مورد استفاده توسط bc برای نمایش یک عدد است و مقیاس اعشار، تعداد کل ارقام ده‌دهی پس از ممیز (نقطه اعشار) است. برای مثال:

.000001 has a length of 6 and scale of 6.
1935.000 has a length of 7 and a scale of 3.

اعداد در دو نوع متغیر ذخیره می‌شوند: متغیرهای ساده و آرایه‌ها. هر دو نوع متغیرهای ساده و متغیرهای آرایه‌ای دارای نام هستند. نام‌ها با یک حرف آغاز می‌شوند و در ادامه می‌توانند شامل هر تعداد حرف، رقم و خط زیرین (underscore) باشند. تمامی حروف باید کوچک باشند. (نام‌های متشکل از حروف و ارقام کامل یک افزونه هستند. در POSIX bc تمامی نام‌ها تنها از یک حرف کوچک تشکیل می‌شوند.) نوع متغیر بر اساس متن مشخص است، چرا که نام همه متغیرهای آرایه‌ای با کروشه ([]) دنبال می‌شود.

چهار متغیر ویژه وجود دارد: scale، ibase، obase و last. متغیر scale تعیین می‌کند که چگونه برخی عملیات‌ها از ارقام پس از ممیز اعشار استفاده کنند. مقدار پیش‌فرض scale برابر 0 است. ibase و obase مبنای تبدیل را برای اعداد ورودی و خروجی مشخص می‌کنند. پیش‌فرض برای هر دو ورودی و خروجی مبنای 10 است. متغیر last (یک افزونه) متغیری است که مقدار آخرین عدد چاپ‌شده را در بر دارد. این متغیرها در ادامه در بخش‌های مناسب با جزئیات بیشتر بررسی خواهند شد. می‌توان به تمامی این متغیرها مقدار نسبت داد و همچنین از آن‌ها در عبارت‌ها استفاده کرد.

توضیحات در bc با نویسه‌های /* آغاز شده و با نویسه‌های */ پایان می‌یابند. توضیحات می‌توانند در هر جایی آغاز شوند و در ورودی به عنوان یک فاصله منفرد در نظر گرفته می‌شوند. (این امر سبب می‌شود که توضیحات به عنوان جداکننده سایر عناصر ورودی عمل کنند؛ برای نمونه، توضیحات نمی‌توانند در میانه نام یک متغیر قرار گیرند.) توضیحات شامل هرگونه خط جدید (انتهای خط) میان ابتدا و انتهای توضیح نیز می‌شوند.

به منظور پشتیبانی از اسکریپت‌ها در bc، توضیحات تک‌خطی به عنوان یک افزونه اضافه شده است. یک توضیح تک‌خطی با نویسه # آغاز می‌شود و تا انتهای همان خط ادامه می‌یابد. نویسه انتهای خط جزئی از توضیح محسوب نمی‌شود و به صورت عادی پردازش می‌گردد.

اعداد توسط عبارت‌ها و دستورها مدیریت و پردازش می‌شوند. از آنجا که این زبان برای حالت تعاملی طراحی شده است، دستورها و عبارت‌ها در سریع‌ترین زمان ممکن اجرا می‌شوند. هیچ برنامه اصلی وجود ندارد؛ در عوض، کدها به محض روبرو شدن اجرا می‌شوند. (توابع که بعداً با جزئیات بررسی خواهند شد، به محض مشاهده شدن تعریف می‌شوند.)

یک عبارت ساده فقط یک مقدار ثابت است. bc مقادیر ثابت را با استفاده از مبنای ورودی فعلی که توسط متغیر ibase تعیین می‌شود، به اعداد ده‌دهی داخلی تبدیل می‌کند (استثنایی در توابع وجود دارد). مقادیر معتبر برای ibase از 2 تا 36 است (مبناهای بزرگتر از 16 یک افزونه هستند). انتساب مقداری خارج از این محدوده به ibase منجر به مقدار 2 یا 36 خواهد شد. اعداد ورودی می‌توانند شامل نویسه‌های 0–9 و A–Z باشند. (توجه: حروف باید بزرگ باشند؛ حروف کوچک نام‌های متغیر هستند.) اعداد تک‌رقمی همواره مقدار همان رقم را فارغ از مقدار ibase دارند (برای مثال A = 10). برای اعداد چندرقمی، bc تمام ارقام ورودی بزرگتر یا مساوی با ibase را به مقدار ibase-1 تغییر می‌دهد. این امر سبب می‌شود که عدد ZZZ همواره بزرگترین عدد ۳ رقمی در مبنای ورودی باشد.

عبارت‌های کامل مشابه بسیاری از زبان‌های سطح بالای دیگر هستند. از آنجا که تنها یک نوع عدد وجود دارد، هیچ قاعده‌ای برای ترکیب انواع مختلف وجود ندارد؛ در عوض، قواعدی بر روی مقیاس اعشار (scale) عبارت‌ها وجود دارد. هر عبارتی دارای یک مقیاس اعشار است. این مقدار از مقیاس اعشار اعداد اولیه، عملیات انجام‌شده و در بسیاری از موارد از مقدار متغیر scale به دست می‌آید. مقادیر مجاز برای متغیر scale از 0 تا بیشترین عدد قابل نمایش توسط یک عدد صحیح در زبان C است.

در توضیحات زیر درباره عبارت‌های معتبر، «expr» به یک عبارت کامل و «var» به یک متغیر ساده یا آرایه‌ای اشاره دارد. یک متغیر ساده به شکل

name
و یک متغیر آرایه‌ای به صورت
name[expr]
مشخص می‌شود. مگر در مواردی که صراحتاً ذکر شود، مقیاس اعشار نتیجه، برابر با بیشترین مقیاس اعشار در میان عبارت‌های به کار رفته است.
نتیجه، قرینه عبارت است.
++ var
یک واحد به متغیر افزوده می‌شود و مقدار جدید نتیجه عبارت است.
یک واحد از متغیر کاسته می‌شود و مقدار جدید نتیجه عبارت است.
نتیجه عبارت، مقدار متغیر است و سپس یک واحد به متغیر افزوده می‌شود.
نتیجه عبارت، مقدار متغیر است و سپس یک واحد از متغیر کاسته می‌شود.
نتیجه عبارت، مجموع دو عبارت است.
نتیجه عبارت، تفاضل دو عبارت است.
نتیجه عبارت، حاصل‌ضرب دو عبارت است.
نتیجه عبارت، حاصل‌تقسیم دو عبارت است. مقیاس اعشار نتیجه، مقدار متغیر scale خواهد بود.
نتیجه عبارت، «باقی‌مانده» است و به روش زیر محاسبه می‌شود: برای محاسبه a%b، ابتدا a/b با دقت ارقام scale محاسبه می‌شود. از آن نتیجه برای محاسبه a-(a/b)*b با مقیاسی برابر با بیشینه scale+scale(b) و scale(a) استفاده می‌گردد. اگر scale روی صفر تنظیم شده باشد و هر دو عبارت عدد صحیح باشند، این عبارت همان تابع باقی‌مانده تقسیم صحیح است.
نتیجه عبارت، مقدار عبارت اول به توان عبارت دوم است. عبارت دوم باید یک عدد صحیح باشد (اگر عبارت دوم عدد صحیح نباشد، هشداری صادر شده و عبارت برای رسیدن به یک مقدار عدد صحیح بریده می‌شود). اگر توان منفی باشد، مقیاس اعشار نتیجه برابر scale خواهد بود. اگر توان مثبت باشد، مقیاس اعشار نتیجه برابر با کمینه حاصل‌ضرب مقیاس اعشار عبارت اول در مقدار توان و بیشینه scale و مقیاس اعشار عبارت اول خواهد بود؛ یعنی: (scale(a^b) = min(scale(a)*b, max(scale, scale(a)))). باید توجه داشت که expr^0 همواره مقدار 1 را برمی‌گرداند.
( expr )
این حالت، تقدم استاندارد عملگرها را تغییر می‌دهد تا محاسبه عبارت اجباری شود.
مقدار عبارت به متغیر انتساب داده می‌شود.
این معادل "var = var <op> expr" است، با این تفاوت که بخش "var" تنها یک بار ارزیابی می‌شود. این تفاوت در صورتی که "var" یک آرایه باشد می‌تواند مؤثر واقع شود.

عبارت‌های رابطه‌ای نوع خاصی از عبارت‌ها هستند که همواره به 0 یا 1 ارزیابی می‌شوند؛ اگر رابطه نادرست باشد 0 و اگر رابطه درست باشد 1. این‌ها می‌توانند در هر عبارت معتبری ظاهر شوند. (استاندارد POSIX bc ایجاب می‌کند که عبارت‌های رابطه‌ای فقط در دستورهای if، while و for به کار روند و در آن‌ها تنها یک آزمون رابطه‌ای انجام شود.) عملگرهای رابطه‌ای عبارتند از:

اگر expr1 اکیداً کوچکتر از expr2 باشد، نتیجه 1 است.
اگر expr1 کوچکتر یا مساوی expr2 باشد، نتیجه 1 است.
اگر expr1 اکیداً بزرگتر از expr2 باشد، نتیجه 1 است.
اگر expr1 بزرگتر یا مساوی expr2 باشد، نتیجه 1 است.
اگر expr1 برابر با expr2 باشد، نتیجه 1 است.
اگر expr1 با expr2 برابر نباشد، نتیجه 1 است.

عملیات بولی نیز معتبر هستند (استاندارد POSIX bc فاقد عملیات بولی است). نتیجه تمامی عملیات بولی همانند عبارت‌های رابطه‌ای 0 و 1 (برای نادرست و درست) است. عملگرهای بولی عبارتند از:

!expr
اگر expr برابر 0 باشد، نتیجه 1 است.
اگر هر دو عبارت غیر صفر باشند، نتیجه 1 است.
اگر هر یک از دو عبارت غیر صفر باشد، نتیجه 1 است.

تقدم عملگرها در عبارت به شرح زیر است: (از کمترین به بیشترین)

عملگر ||، شرکت‌پذیر از چپ
عملگر &&، شرکت‌پذیر از چپ
عملگر !، غیرشرکت‌پذیر
عملگرهای رابطه‌ای، شرکت‌پذیر از چپ
عملگر انتساب، شرکت‌پذیر از راست
عملگرهای + و -، شرکت‌پذیر از چپ
عملگرهای *، / و %، شرکت‌پذیر از چپ
عملگر ^، شرکت‌پذیر از راست
عملگر یکانی -، غیرشرکت‌پذیر
عملگرهای ++ و --، غیرشرکت‌پذیر

این اولویت‌بندی به گونه‌ای برگزیده شده است که برنامه‌های bc سازگار با POSIX به درستی اجرا شوند. این امر موجب می‌شود که استفاده از عملگرهای رابطه‌ای و منطقی همراه با عبارت‌های انتساب رفتار نامعمولی داشته باشد. عبارت زیر را در نظر بگیرید:

a = 3 < 5

بیشتر برنامه‌نویسان C تصور می‌کنند این عبارت نتیجه "3 < 5" (مقدار 1) را به متغیر "a" نسبت می‌دهد. اما کاری که bc انجام می‌دهد این است که مقدار 3 را به متغیر "a" نسبت داده و سپس 3 را با 5 مقایسه می‌کند. بنابراین هنگام استفاده از عملگرهای رابطه‌ای و منطقی همراه با عملگرهای انتساب، بهتر است از پرانتز استفاده شود.

چندین عبارت ویژه دیگر در bc ارائه شده است. این موارد به توابع تعریف‌شده توسط کاربر و توابع استاندارد مربوط می‌شوند. همگی به صورت "name(parameters)" ظاهر می‌شوند. برای توابع تعریف‌شده توسط کاربر به بخش توابع مراجعه کنید. توابع استاندارد عبارتند از:

مقدار تابع length تعداد ارقام معنادار در عبارت است.
تابع read (یک افزونه)، صرف‌نظر از جایی که تابع در آن رخ می‌دهد، یک عدد را از ورودی استاندارد می‌خواند. مراقب باشید، این امر ممکن است سبب بروز مشکلاتی در ترکیب داده و برنامه در ورودی استاندارد شود. بهترین کاربرد برای این تابع در برنامه‌های از پیش نوشته‌شده‌ای است که نیاز به دریافت ورودی از کاربر دارند اما هرگز اجازه ورود کد برنامه از سوی کاربر را نمی‌دهند. مقدار تابع read همان عدد خوانده‌شده از ورودی استاندارد است که با استفاده از مقدار فعلی متغیر ibase به عنوان مبنای تبدیل، پردازش می‌شود.
مقدار تابع scale تعداد ارقام پس از ممیز اعشار در عبارت است.
مقدار تابع sqrt ریشه دوم (جذر) عبارت است. اگر عبارت منفی باشد، خطای زمان اجرا تولید می‌شود.

دستورها (همانند بیشتر زبان‌های جبری) توالی ارزیابی عبارت‌ها را فراهم می‌کنند. در bc دستورها در سریع‌ترین زمان ممکن اجرا می‌شوند. اجرا زمانی رخ می‌دهد که یک خط جدید مشاهده شود و یک یا چند دستور کامل وجود داشته باشد. به دلیل این اجرای بی‌درنگ، خطوط جدید در bc بسیار حائز اهمیت هستند. در واقع هم نقطه-ویرگول و هم خط جدید به عنوان جداکننده دستورها به کار می‌روند. یک خط جدید که در جای نامناسب قرار گرفته باشد سبب خطای نحوی خواهد شد. از آنجا که خطوط جدید جداکننده دستور هستند، با استفاده از نویسه بک‌اسلش می‌توان یک خط جدید را پنهان کرد. توالی "\<nl>" که در آن <nl> خط جدید است، در bc به عنوان فاصله خالی در نظر گرفته می‌شود نه خط جدید. یک فهرست دستور (statement list) مجموعه‌ای از دستورها است که با نقطه-ویرگول و خط جدید از یکدیگر جدا شده‌اند. در ادامه فهرستی از دستورهای bc و عملکرد آن‌ها آمده است: (مواردی که در کروشه ([]) قرار دارند بخش‌های اختیاری دستور هستند.)

این دستور یکی از دو کار را انجام می‌دهد: اگر عبارت با "<variable> <assignment> ..." آغاز شود، یک دستور انتساب تلقی می‌شود. اگر عبارت دستور انتساب نباشد، ارزیابی شده و در خروجی چاپ می‌گردد. پس از چاپ شدن عدد، یک خط جدید چاپ می‌شود. برای مثال، "a=1" یک دستور انتساب است و "(a=1)" عبارتی است که شامل یک انتساب توکار است. تمامی اعدادی که چاپ می‌شوند، در مبنایی چاپ می‌گردند که توسط متغیر obase مشخص شده است. مقادیر معتبر برای obase از 2 تا BC_BASE_MAX است (بخش محدودیت‌ها را ببینید). برای مبناهای 2 تا 16، روش معمول نوشتن اعداد استفاده می‌شود. برای مبناهای بزرگتر از 16، bc از روش ارقام چندنویسه‌ای برای چاپ اعداد استفاده می‌کند که در آن هر رقم در مبنای بالاتر به عنوان یک عدد در مبنای 10 چاپ می‌شود. ارقام چندنویسه‌ای با فاصله از یکدیگر جدا می‌شوند. هر رقم شامل تعداد نویسه‌های لازم برای نمایش مقدار ده‌دهی "obase-1" است. از آنجا که اعداد دارای دقت دلخواه هستند، ممکن است برخی اعداد در یک خط خروجی جا نشوند. این اعداد طولانی با قرار دادن "\" به عنوان آخرین نویسه روی خط، در چندین خط تقسیم می‌شوند. بیشینه تعداد نویسه‌های چاپ‌شده در هر خط 70 است. با توجه به ماهیت تعاملی bc، چاپ یک عدد سبب این اثر جانبی می‌شود که مقدار چاپ‌شده به متغیر ویژه last نسبت داده شود. این به کاربر اجازه می‌دهد تا بدون نیاز به تایپ مجدد عبارتی که عدد را چاپ کرده است، آخرین مقدار چاپ‌شده را بازیابی کند. انتساب مقدار به last مجاز است و مقدار جدید را روی آخرین مقدار چاپ‌شده بازنویسی می‌کند. مقدار تازه انتساب‌داده‌شده تا زمانی که عدد بعدی چاپ شود یا مقدار دیگری به last نسبت داده شود باقی می‌ماند. (برخی نصب‌ها ممکن است اجازه استفاده از یک نقطه تک (.) که جزئی از یک عدد نیست را به عنوان نماد اختصاری برای last بدهند.)
رشته در خروجی چاپ می‌شود. رشته‌ها با یک نویسه نقل‌قول دوگانه (double quote) آغاز می‌شوند و شامل تمامی نویسه‌ها تا نقل‌قول دوگانه بعدی هستند. تمامی نویسه‌ها دقیقاً همان‌طور که هستند دریافت می‌شوند، از جمله هر خط جدید. پس از رشته هیچ نویسه خط جدیدی چاپ نمی‌شود.
دستور print (یک افزونه) روش دیگری برای خروجی فراهم می‌کند. "list" فهرستی از رشته‌ها و عبارت‌ها است که با کاما از یکدیگر جدا شده‌اند. هر رشته یا عبارت به ترتیب فهرست چاپ می‌شود. هیچ خط جدید پایانی چاپ نمی‌شود. عبارت‌ها ارزیابی شده و مقدار آن‌ها چاپ می‌شود و به متغیر last نسبت داده می‌شود. رشته‌ها در دستور print در خروجی چاپ می‌شوند و می‌توانند شامل نویسه‌های ویژه باشند. نویسه‌های ویژه با نویسه بک‌اسلش (\) آغاز می‌شوند. نویسه‌های ویژه شناخته‌شده توسط bc عبارتند از: "a" (هشدار یا زنگ)، "b" (پس‌بر یا backspace)، "f" (برگه جدید یا form feed)، "n" (خط جدید)، "r" (بازگشت به ابتدای سطر یا carriage return)، "q" (نقل‌قول دوگانه)، "t" (تب) و "\" (بک‌اسلش). هر نویسه دیگری پس از بک‌اسلش نادیده گرفته خواهد شد.
{ statement_list }
این دستور مرکب است. به چندین دستور اجازه می‌دهد برای اجرا در یک گروه قرار گیرند.
دستور if عبارت را ارزیابی کرده و بسته به مقدار عبارت، statement1 یا statement2 را اجرا می‌کند. اگر عبارت غیر صفر باشد، statement1 اجرا می‌شود. اگر statement2 موجود باشد و مقدار عبارت 0 باشد، statement2 اجرا خواهد شد. (بند else یک افزونه است.)
دستور while تا زمانی که عبارت غیر صفر باشد دستور statement را اجرا می‌کند. این دستور عبارت را پیش از هر بار اجرای دستور ارزیابی می‌کند. پایان حلقه در اثر صفر شدن مقدار عبارت یا اجرای دستور break رخ می‌دهد.
دستور for اجرای مکرر دستور را کنترل می‌کند. Expression1 پیش از حلقه ارزیابی می‌شود. Expression2 پیش از هر بار اجرای دستور ارزیابی می‌گردد. اگر غیر صفر باشد، دستور ارزیابی می‌شود. اگر صفر باشد، حلقه پایان می‌یابد. پس از هر بار اجرای دستور، expression3 پیش از ارزیابی مجدد expression2 محاسبه می‌شود. اگر expression1 یا expression3 وجود نداشته باشند، در جایی که باید ارزیابی می‌شدند چیزی ارزیابی نمی‌شود. اگر expression2 وجود نداشته باشد، همانند جایگزین کردن مقدار 1 به جای expression2 است. (اختیاری بودن این عبارت‌ها یک افزونه است؛ استاندارد POSIX bc وجود هر سه عبارت را الزامی می‌داند.) کد زیر معادل دستور for است:
expression1;
while (expression2) {
   statement;
   expression3;
}
این دستور سبب خروج اجباری از نزدیک‌ترین دستور while یا دستور for دربرگیرنده می‌شود.
دستور continue (یک افزونه) سبب می‌شود نزدیک‌ترین دستور for دربرگیرنده، تکرار بعدی را آغاز کند.
دستور halt (یک افزونه) دستوری قابل اجرا است که سبب می‌شود پردازنده bc تنها زمانی که این دستور اجرا می‌شود خاتمه یابد. برای مثال، "if (0 == 1) halt" سبب پایان یافتن bc نخواهد شد زیرا halt اجرا نمی‌شود.
بازگرداندن مقدار 0 از یک تابع. (بخش توابع را ببینید.)
بازگرداندن مقدار عبارت از یک تابع. (بخش توابع را ببینید.) به عنوان یک افزونه، استفاده از پرانتز الزامی نیست.

این دستورها به معنای سنتی دستور نیستند. آن‌ها دستورهای اجرایی نیستند؛ عملکرد آن‌ها در زمان «کامپایل» انجام می‌گیرد.

چاپ محدودیت‌های محلی اعمال‌شده توسط نسخه محلی bc. این یک افزونه است.
هنگامی که دستور quit خوانده می‌شود، پردازنده bc صرف‌نظر از جایی که دستور quit در آن یافت شده است خاتمه می‌یابد. برای مثال، "if (0 == 1) quit" سبب پایان یافتن bc خواهد شد.
چاپ اطلاعیه ضمانت‌نامه طولانی‌تر. این یک افزونه است.

توابع روشی برای تعریف یک محاسبه فراهم می‌کنند که بعداً بتواند اجرا شود. توابع در bc همواره مقداری را محاسبه کرده و آن را به فراخواننده بازمی‌گردانند. تعریف توابع «پویا» است، به این معنی که یک تابع تا زمانی که تعریفی برای آن در ورودی دیده نشود، تعریف‌نشده باقی می‌ماند. سپس آن تعریف مورد استفاده قرار می‌گیرد تا اینکه تعریف دیگری برای همان نام دیده شود. سپس تعریف جدید جایگزین تعریف قدیمی‌تر خواهد شد. یک تابع به صورت زیر تعریف می‌شود:

define name ( parameters ) { newline
    auto_list   statement_list }

فراخوانی تابع صرفاً عبارتی به شکل "name(parameters)" است.

پارامترها، عدد یا آرایه هستند (یک افزونه). در تعریف تابع، صفر یا چند پارامتر با ذکر نام‌هایشان که با کاما از یکدیگر جدا شده‌اند تعریف می‌شوند. تمام پارامترها به صورت فراخوانی با مقدار (call by value) هستند. آرایه‌ها در تعریف پارامتر با نماد "name[]" مشخص می‌شوند. در فراخوانی تابع، پارامترهای واقعی برای پارامترهای عددی عبارت‌های کامل هستند. همان نمادی که برای تعریف پارامترهای آرایه‌ای استفاده شد برای ارسال آرایه‌ها نیز به کار می‌رود. آرایه نام‌گذاری‌شده با مقدار به تابع ارسال می‌شود. از آنجا که تعریف توابع پویا است، تعداد و نوع پارامترها در هنگام فراخوانی تابع بررسی می‌شوند. هرگونه عدم تطابق در تعداد یا نوع پارامترها سبب خطای زمان اجرا خواهد شد. همچنین خطای زمان اجرا در صورت فراخوانی یک تابع تعریف‌نشده نیز رخ خواهد داد.

فهرست auto_list فهرستی اختیاری از متغیرها است که برای استفاده «محلی» به کار می‌روند. نحو فهرست متغیرهای خودکار (در صورت وجود) به صورت "auto name, ... ;" است (نقطه-ویرگول اختیاری است). هر name نام یک متغیر خودکار (auto) است. آرایه‌ها می‌توانند با استفاده از همان نمادی که در پارامترها استفاده شد مشخص شوند. مقادیر این متغیرها در ابتدای تابع بر روی یک پشته قرار می‌گیرند (push). سپس متغیرها با صفر مقداردهی اولیه شده و در طول اجرای تابع استفاده می‌شوند. در هنگام خروج از تابع، این متغیرها از پشته برداشته می‌شوند (pop) تا مقدار اولیه آن‌ها (در زمان فراخوانی تابع) بازیابی شود. پارامترها در واقع متغیرهای خودکاری هستند که با مقداری که در فراخوانی تابع ارائه شده است مقداردهی اولیه می‌شوند. متغیرهای خودکار با متغیرهای محلی سنتی متفاوت هستند، زیرا اگر تابع A تابع B را فراخوانی کند، B می‌تواند صرفاً با استفاده از همان نام به متغیرهای خودکار تابع A دسترسی یابد، مگر آنکه تابع B نیز آن‌ها را به عنوان متغیر خودکار تعریف کرده باشد. با توجه به این واقعیت که متغیرهای خودکار و پارامترها روی یک پشته قرار می‌گیرند، bc از توابع بازگشتی پشتیبانی می‌کند.

بدنه تابع فهرستی از دستورهای bc است. باز هم دستورها با نقطه-ویرگول یا خطوط جدید جدا می‌شوند. دستورهای return سبب پایان تابع و بازگرداندن یک مقدار می‌شوند. دو نسخه از دستور return وجود دارد: شکل اول، "return"، مقدار 0 را به عبارت فراخواننده بازمی‌گرداند. شکل دوم، "return ( expression )"، مقدار عبارت را محاسبه کرده و آن مقدار را به عبارت فراخواننده بازمی‌گرداند. یک "return (0)" ضمنی در انتهای هر تابع وجود دارد. این ویژگی به تابع اجازه می‌دهد بدون دستور صریح return خاتمه یافته و مقدار 0 را برگرداند.

توابع همچنین نحوه استفاده از متغیر ibase را تغییر می‌دهند. تمامی مقادیر ثابت در بدنه تابع با استفاده از مقدار ibase در زمان فراخوانی تابع تبدیل می‌شوند. تغییرات ibase در طول اجرای تابع نادیده گرفته می‌شوند، به جز برای تابع استاندارد read که همواره از مقدار فعلی ibase برای تبدیل اعداد استفاده می‌کند.

چندین افزونه به توابع اضافه شده است. نخست، قالب تعریف تا حدی انعطاف‌پذیرتر شده است. استاندارد ایجاب می‌کند که آکولاد باز در همان خط کلیدواژه define باشد و سایر بخش‌ها در خطوط بعدی قرار گیرند. این نسخه از bc اجازه می‌دهد هر تعداد خط جدید قبل و بعد از آکولاد باز تابع قرار گیرد. برای مثال، تعریف‌های زیر معتبر هستند:


define d (n) { return (2*n); }
define d (n)
  { return (2*n); }

توابع می‌توانند به صورت void تعریف شوند. یک تابع void هیچ مقداری بازنمی‌گرداند و بنابراین نمی‌تواند در هیچ جایی که به مقدار نیاز دارد استفاده شود. یک تابع void هنگامی که به تنهایی در یک خط ورودی فراخوانی شود هیچ خروجی تولید نمی‌کند. کلیدواژه void بین کلیدواژه define و نام تابع قرار می‌گیرد. برای مثال، نشست زیر را در نظر بگیرید:


define py (y) { print "--->", y, "<---", "\n"; }
define void px (x) { print "--->", x, "<---", "\n"; }
py(1)
--->1<---
0
px(1)
--->1<---
از آنجا که py یک تابع void نیست، فراخوانی py(1) خروجی مورد نظر را چاپ می‌کند و سپس خط دومی را که مقدار تابع است چاپ می‌نماید. از آنجا که مقدار تابعی که دستور صریح return ندارد صفر است، عدد صفر چاپ می‌شود. برای px(1)، هیچ صفری چاپ نمی‌شود زیرا این تابع یک تابع void است.

همچنین، فراخوانی با متغیر (ارجاع) برای آرایه‌ها اضافه شده است. برای اعلان یک آرایه با فراخوانی ارجاعی، اعلان پارامتر آرایه در تعریف تابع به شکل "*name[]" خواهد بود. فراخوانی تابع همچنان مانند آرایه‌های فراخوانی با مقدار باقی می‌ماند.

اگر bc با گزینه -l فراخوانی شود، یک کتابخانه ریاضی از پیش بارگذاری می‌شود و مقیاس اعشار پیش‌فرض (scale) روی 20 تنظیم می‌گردد. توابع ریاضی نتایج خود را با مقیاس اعشاری که در زمان فراخوانی آن‌ها تنظیم شده است محاسبه خواهند کرد. کتابخانه ریاضی توابع زیر را تعریف می‌کند:

سینوس x، مقدار x بر حسب رادیان است.
کسینوس x، مقدار x بر حسب رادیان است.
آرک‌تانژانت x، آرک‌تانژانت رادیان برمی‌گرداند.
لگاریتم طبیعی x.
تابع نمایی، e به توان مقدار x.
تابع بسل (Bessel) از مرتبه صحیح n از x.

در /bin/sh، دستور زیر مقدار عدد پی ("pi") را به متغیر شل pi اختصاص می‌دهد:

pi=$(echo "scale=10; 4*a(1)" | bc -l)

کد زیر تعریف تابع نمایی به کار رفته در کتابخانه ریاضی است. این تابع با استاندارد POSIX bc نوشته شده است:


scale = 20
/* Uses the fact that e^x = (e^(x/2))^2
   When x is small enough, we use the series:
     e^x = 1 + x + x^2/2! + x^3/3! + ...
*/
define e(x) {
  auto  a, d, e, f, i, m, v, z
  /* Check the sign of x. */
  if (x<0) {
    m = 1
    x = -x
  }
  /* Precondition x. */
  z = scale;
  scale = 4 + z + .44*x;
  while (x > 1) {
    f += 1;
    x /= 2;
  }
  /* Initialize the variables. */
  v = 1+x
  a = x
  d = 1
  for (i=2; 1; i++) {
    e = (a *= x) / (d *= i)
    if (e == 0) {
      if (f>0) while (f--)  v = v*v;
      scale = z
      if (m) return (1/v);
      return (v/1);
    }
    v += e
  }
}

کد زیر برنامه‌ای ساده برای محاسبه موجودی دسته‌چک است که از قابلیت‌های گسترش‌یافته bc استفاده می‌کند. بهتر است این برنامه در یک پرونده نگهداری شود تا بتوان بدون نیاز به تایپ مجدد در هر بار، بارها از آن استفاده کرد:


scale=2
print "\nCheck book program!\n"
print "  Remember, deposits are negative transactions.\n"
print "  Exit by a 0 transaction.\n\n"
print "Initial balance? "; bal = read()
bal /= 1
print "\n"
while (1) {
  "current balance = "; bal
  "transaction? "; trans = read()
  if (trans == 0) break;
  bal -= trans
  bal /= 1
}
quit

کد زیر تعریف تابع فاکتوریل بازگشتی است:


define f (x) {
  if (x <= 1) return (1);
  return (f(x-1) * x);
}

برنامه GNU bc می‌تواند (از طریق یک گزینه پیکربندی) طوری کامپایل شود که از کتابخانه ویرایشگر ورودی GNU readline یا کتابخانه BSD libedit استفاده کند. این قابلیت به کاربر امکان می‌دهد خطوط را پیش از ارسال به bc ویرایش کند. همچنین تاریخچه‌ای از خطوط تایپ‌شده قبلی را فراهم می‌سازد. هنگامی که این گزینه انتخاب شده باشد، bc یک متغیر ویژه دیگر خواهد داشت: این متغیر ویژه، history، تعداد خطوط تاریخچه نگهداری‌شده است. برای readline، مقدار -1 به معنای نگهداری تعداد نامحدودی از خطوط تاریخچه است. تنظیم مقدار history روی یک عدد مثبت، تعداد خطوط تاریخچه را به همان عدد محدود می‌کند. مقدار 0 قابلیت تاریخچه را غیرفعال می‌سازد. مقدار پیش‌فرض 100 است. برای اطلاعات بیشتر، راهنمای کاربری کتابخانه‌های GNU readline، history و BSD libedit را مطالعه کنید. نمی‌توان هم‌زمان هر دو کتابخانه readline و libedit را فعال کرد.

این نسخه از bc بر اساس پیش‌نویس POSIX P1003.2/D11 پیاده‌سازی شده است و شامل تفاوت‌ها و افزونه‌های متعددی نسبت به پیش‌نویس و پیاده‌سازی‌های سنتی است. این نسخه به روش سنتی با استفاده از dc(1) پیاده‌سازی نشده است. این نسخه یک فرآیند واحد است که ترجمه بایت‌کد برنامه را تجزیه کرده و اجرا می‌کند. یک گزینه «مستند‌نشده» (-c) وجود دارد که سبب می‌شود برنامه به جای اجرای بایت‌کد، آن را در خروجی استاندارد بنویسد. این گزینه عمدتاً برای اشکال‌زدایی تجزیه‌کننده و آماده‌سازی کتابخانه ریاضی استفاده می‌شد.

منبع اصلی تفاوت‌ها، افزونه‌ها (جایی که قابلیتی برای افزودن کارایی بیشتر گسترش یافته است) و افزوده‌ها (جایی که قابلیت‌های جدیدی اضافه شده‌اند) هستند. فهرست تفاوت‌ها و افزونه‌ها به شرح زیر است:

محیط LANG
این نسخه در پردازش متغیر محیطی LANG و تمامی متغیرهای محیطی که با _LC آغاز می‌شوند با استاندارد POSIX مطابقت ندارد.
نام‌ها
نسخه‌های سنتی و POSIX bc دارای نام‌های تک‌حرفی برای توابع، متغیرها و آرایه‌ها هستند. در این نسخه، نام‌ها به گونه‌ای گسترش یافته‌اند که چندنویسه‌ای باشند، با یک حرف آغاز شوند و بتوانند شامل حروف، ارقام و نویسه خط زیرین باشند.
رشته‌ها
رشته‌ها مجاز به داشتن نویسه NUL نیستند. استاندارد POSIX می‌گوید تمام نویسه‌ها باید در رشته‌ها گنجانده شوند.
متغیر last
استاندارد POSIX bc فاقد متغیر last است. برخی پیاده‌سازی‌های bc از نقطه (.) به روشی مشابه استفاده می‌کنند.
مقایسه‌ها
استاندارد POSIX bc مقایسه‌ها را تنها در دستور if، دستور while و عبارت دوم دستور for مجاز می‌داند. همچنین در هر یک از آن دستورها فقط یک عملیات رابطه‌ای مجاز است.
دستور if و بند else
استاندارد POSIX bc فاقد بند else است.
دستور for
استاندارد POSIX bc حضور تمام عبارت‌ها را در دستور for الزامی می‌داند.
&&، ||، !
استاندارد POSIX bc فاقد عملگرهای منطقی است.
تابع read
استاندارد POSIX bc فاقد تابع read است.
دستور print
استاندارد POSIX bc فاقد دستور print است.
دستور continue
استاندارد POSIX bc فاقد دستور continue است.
دستور return
استاندارد POSIX bc وجود پرانتز در اطراف عبارت return را الزامی می‌داند.
پارامترهای آرایه
استاندارد POSIX bc (در حال حاضر) از پارامترهای آرایه‌ای به طور کامل پشتیبانی نمی‌کند. گرامر POSIX آرایه‌ها را در تعریف توابع مجاز می‌داند، اما روشی برای تعیین آرایه به عنوان یک پارامتر واقعی ارائه نمی‌دهد (این احتمالاً یک سهل‌انگاری در گرامر استاندارد است). پیاده‌سازی‌های سنتی bc تنها از پارامترهای آرایه‌ای با روش فراخوانی با مقدار پشتیبانی می‌کنند.
قالب توابع
استاندارد POSIX bc ایجاب می‌کند که آکولاد باز در همان خط کلیدواژه define و دستور auto در خط بعدی قرار گیرد.
=+, =-, =*, =/, =%, =^
استاندارد POSIX bc تعریف این عملگرهای انتساب «سبک قدیمی» را الزامی نمی‌داند. این نسخه ممکن است این انتساب‌های سبک قدیمی را مجاز بداند. از دستور limits استفاده کنید تا ببینید آیا نسخه نصب‌شده از آن‌ها پشتیبانی می‌کند یا خیر. اگر از عملگرهای انتساب سبک قدیمی پشتیبانی کند، دستور "a =- 1" یک واحد از a کم می‌کند، به جای آنکه مقدار -1 را به a اختصاص دهد.
فاصله‌ها در اعداد
سایر پیاده‌سازی‌های bc وجود فاصله در اعداد را مجاز می‌دانند. برای مثال، "x=1 3" مقدار 13 را به متغیر x اختصاص می‌دهد. همین دستور در این نسخه از bc سبب خطای نحوی می‌شود.
خطاها و اجرا
این پیاده‌سازی از نظر اینکه در هنگام مشاهده خطاهای نحوی و سایر خطاها در برنامه چه کدی اجرا خواهد شد با سایر پیاده‌سازی‌ها متفاوت است. اگر یک خطای نحوی در تعریف تابع پیدا شود، بازیابی خطا تلاش می‌کند ابتدای یک دستور را پیدا کرده و به تجزیه تابع ادامه دهد. هنگامی که یک خطای نحوی در تابع یافت شد، تابع دیگر قابل فراخوانی نخواهد بود و تعریف‌نشده می‌شود. خطاهای نحوی در کد اجرای تعاملی سبب نامعتبر شدن بلوک اجرایی جاری خواهد شد. بلوک اجرایی با یک انتهای خط که پس از دنباله کاملی از دستورها ظاهر می‌شود پایان می‌یابد. برای مثال:
a = 1
b = 2
دارای دو بلوک اجرایی است و:
{ a = 1
  b = 2 }

دارای یک بلوک اجرایی است. هرگونه خطای زمان اجرا اجرای بلوک اجرایی جاری را خاتمه می‌دهد. یک هشدار زمان اجرا، بلوک اجرایی جاری را متوقف نمی‌کند.

سیگنال‌های وقفه (Interrupts)
در طول یک نشست تعاملی، سیگنال SIGINT (که معمولاً توسط نویسه control-C از ترمینال تولید می‌شود) سبب قطع اجرای بلوک اجرایی جاری خواهد شد. این کار یک خطای «زمان اجرا» را نمایش می‌دهد که مشخص می‌کند کدام تابع متوقف شده است. پس از پاک‌سازی تمام ساختارهای زمان اجرا، پیامی چاپ می‌شود تا به کاربر اطلاع دهد که bc آماده دریافت ورودی بیشتر است. تمامی توابع تعریف‌شده قبلی همچنان تعریف‌شده باقی می‌مانند و مقدار تمام متغیرهای غیرخودکار همان مقدار در نقطه وقوع وقفه است. تمامی متغیرهای خودکار و پارامترهای توابع در طول فرآیند پاک‌سازی حذف می‌شوند. در طول یک نشست غیرتعاملی، سیگنال SIGINT کل اجرای bc را خاتمه می‌دهد.

موارد زیر محدودیت‌هایی هستند که در حال حاضر برای این پردازنده bc اعمال شده‌اند. برخی از آن‌ها ممکن است در زمان نصب تغییر یافته باشند. برای مشاهده مقادیر واقعی از دستور limits استفاده کنید.

بیشینه مبنای خروجی دست‌کم 10^9 است. بیشینه مبنای ورودی 16 است.
این مقدار در حال حاضر در توزیع پیش‌فرض یک حد اختیاری 65535 است؛ نصب سیستم شما ممکن است متفاوت باشد.
تعداد ارقام پس از ممیز اعشار به INT_MAX رقم محدود شده است. همچنین تعداد ارقام پیش از ممیز اعشار نیز به INT_MAX رقم محدود است.
محدودیت تعداد نویسه‌ها در یک رشته برابر INT_MAX نویسه است.
توان (exponent)
مقدار توان در عملیات توان‌رسانی (^) به LONG_MAX محدود است.
نام‌های متغیرها (variable names)
محدودیت فعلی برای تعداد نام‌های یکتا برای هر یک از متغیرهای ساده، آرایه‌ها و توابع برابر با 32767 است.

متغیرهای محیطی زیر توسط bc پردازش می‌شوند:

این متغیر همانند گزینه -s عمل می‌کند.
این سازوکار دیگری برای ارسال آرگومان‌ها به bc است. قالب آن همانند شناسه‌های خط فرمان است. این شناسه‌ها در ابتدا پردازش می‌شوند، بنابراین هر پرونده‌ای که در شناسه‌های محیطی ذکر شده باشد پیش از پرونده‌های شناسه‌های خط فرمان پردازش می‌گردد. این قابلیت به کاربر امکان می‌دهد گزینه‌ها و پرونده‌های «استاندارد» را تنظیم کند تا در هر بار اجرای bc پردازش شوند. پرونده‌های موجود در متغیرهای محیطی معمولاً شامل تعاریف توابعی هستند که کاربر تمایل دارد با هر بار اجرای bc تعریف شوند.
این باید یک عدد صحیح باشد که تعداد نویسه‌ها را در یک خط خروجی برای اعداد مشخص می‌کند. این شامل نویسه‌های بک‌اسلش و خط جدید برای اعداد طولانی نیز می‌شود. به عنوان یک افزونه، مقدار صفر قابلیت چندخطی را غیرفعال می‌کند. هر مقدار دیگری از این متغیر که کمتر از 3 باشد، طول خط را روی 70 تنظیم می‌کند.

اگر هر پرونده‌ای در خط فرمان قابل باز شدن نباشد، bc گزارش می‌دهد که پرونده در دسترس نیست و خاتمه می‌یابد. همچنین پیام‌های عیب‌یابی زمان کامپایل و زمان اجرا وجود دارند که باید خودتوضیح باشند.

بازیابی خطا هنوز چندان خوب نیست.

گزارش‌های اشکال را به نشانی زیر ایمیل کنید: bug-bc@gnu.org. حتماً واژه «bc» را در جایی از بخش موضوع (Subject:) بگنجانید.

Philip A. Nelson
philnelson@acm.org

نویسنده مایل است از Steve Sommars (Steve.Sommars@att.com) به خاطر کمک‌های گسترده‌اش در آزمایش این پیاده‌سازی تشکر کند. پیشنهادات عالی بسیاری ارائه شد؛ این ابزار به واسطه مشارکت ایشان محصول بسیار بهتری است.

dc(1)

2025-01-10 GNU Project