GoGPT Best VPN GoSearch

OnWorks فافيكون

perlguts - عبر الإنترنت في السحابة

قم بتشغيل perlguts في موفر الاستضافة المجاني OnWorks عبر Ubuntu Online أو Fedora Online أو محاكي Windows عبر الإنترنت أو محاكي MAC OS عبر الإنترنت

هذا هو أمر perlguts الذي يمكن تشغيله في موفر الاستضافة المجاني OnWorks باستخدام إحدى محطات العمل المجانية المتعددة عبر الإنترنت مثل Ubuntu Online أو Fedora Online أو محاكي Windows عبر الإنترنت أو محاكي MAC OS عبر الإنترنت

برنامج:

اسم


perlguts - مقدمة في Perl API

الوصف


يحاول هذا المستند وصف كيفية استخدام Perl API، بالإضافة إلى تقديم بعض المعلومات
معلومات عن الأعمال الأساسية لنواة بيرل. إنها بعيدة عن الاكتمال وربما
يحتوي على العديد من الأخطاء. يرجى الرجوع إلى أي أسئلة أو تعليقات للمؤلف أدناه.

المتغيرات


أنواع البيانات
يحتوي Perl على ثلاثة أنواع من أنواع البيانات التي تتعامل مع أنواع البيانات الرئيسية الثلاثة في Perl:

القيمة العددية SV
قيمة صفيف AV
قيمة تجزئة الجهد العالي

يحتوي كل typedef على إجراءات محددة تتعامل مع أنواع البيانات المختلفة.

ابحث عن is an "الرابع"؟
يستخدم Perl typedef IV خاصًا وهو نوع عدد صحيح موقّع بسيط ومضمون
تكون كبيرة بما يكفي لحمل المؤشر (بالإضافة إلى عدد صحيح). بالإضافة إلى ذلك، هناك الأشعة فوق البنفسجية،
وهو ببساطة IV غير موقع.

تستخدم لغة Perl أيضًا نوعين خاصين من أنواع الكتابة، I32 وI16، والتي ستكون دائمًا 32 بت على الأقل
و16 بت طويلة، على التوالي. (مرة أخرى، هناك U32 وU16 أيضًا).
عادة ما يكون طولهما 32 و16 بت بالضبط، ولكن في Crays سيكون طولهما 64 بت.

العمل مع SVS
يمكن إنشاء SV وتحميله بأمر واحد. هناك خمسة أنواع من القيم التي يمكن
يتم تحميلها: قيمة عددية (IV)، وقيمة عددية غير موقعة (UV)، وقيمة مزدوجة (NV)، وسلسلة
(PV)، وحجم آخر (SV). ("PV" تعني "قيمة المؤشر". قد تعتقد أنها كذلك
تمت تسميته بشكل خاطئ لأنه تم وصفه على أنه يشير فقط إلى السلاسل النصية. ومع ذلك، فمن الممكن
لجعله يشير إلى أشياء أخرى. على سبيل المثال، يمكن أن يشير إلى مجموعة من الأشعة فوق البنفسجية. لكن،
استخدامه لغير القيود يتطلب الحذر، حيث أن الافتراض الأساسي لكثير من
الداخلي هو أن PVs مخصصة للسلاسل فقط. في كثير من الأحيان، على سبيل المثال، زائدة "NUL" هي
تم لصقها تلقائيًا. تم توثيق الاستخدام غير المتسلسلة فقط في هذه الفقرة.)

الروتينات السبعة هي:

SV* newSViv(IV);
SV* newSVuv(UV);
SV* newSVnv(double);
SV* newSVpv(const char*, STRLEN);
SV* newSVpvn(const char*, STRLEN);
SV* newSVpvf(const char*, ...);
SV* newSVsv(SV*);

"STRLEN" هو نوع عدد صحيح (Size_t، يتم تعريفه عادةً على أنه size_t in التكوين.ح) مضمونة ل
تكون كبيرة بما يكفي لتمثيل حجم أي سلسلة يمكن لـ Perl التعامل معها.

في الحالة غير المحتملة التي يتطلب فيها SV تهيئة أكثر تعقيدًا، يمكنك إنشاء ملف
SV فارغ مع newSV(len). إذا كانت قيمة "len" تساوي 0، فسيتم إرجاع SV فارغ من النوع NULL، وإلا فسيتم إرجاع SV
يتم إرجاع النوع PV مع len + 1 (بالنسبة إلى "NUL") من وحدات التخزين المخصصة والتي يمكن الوصول إليها
عبر SvPVX. في كلتا الحالتين، يكون لـ SV قيمة undef.

إس في * إس في = newSV(0)؛ /* لم يتم تخصيص مساحة تخزينية */
إس في * إس في = newSV(10)؛ /* 10 (+1) بايت من مساحة التخزين غير المهيأة
*المخصصة*/

لتغيير قيمة أ موجود سابقا SV، هناك ثمانية إجراءات:

باطلة sv_setiv(SV*, IV);
باطلة sv_setuv(SV*, UV);
void sv_setnv(SV*, double);
void sv_setpv(SV*, const char*);
باطلة sv_setpvn(SV*, const char*, STRLEN)
void sv_setpvf(SV*, const char*, ...);
باطلة sv_vsetpvfn(SV*, const char*, STRLEN, va_list *,
SV **، I32، منطقي *)؛
باطلة sv_setsv(SV*, SV*);

لاحظ أنه يمكنك اختيار تحديد طول السلسلة التي سيتم تعيينها باستخدام
"sv_setpvn" أو "newSVpvn" أو "newSVpv"، أو يمكنك السماح لـ Perl بحساب الطول بواسطة
باستخدام "sv_setpv" أو عن طريق تحديد 0 كوسيطة ثانية لـ "newSVpv". كن حذرا،
على الرغم من ذلك، فإن لغة Perl ستحدد طول السلسلة باستخدام "strlen"، والذي يعتمد على
السلسلة التي تنتهي بحرف "NUL"، ولا تحتوي على NULs.

تتم معالجة وسيطات "sv_setpvf" مثل "sprintf" والمخرجات المنسقة
تصبح القيمة.

"sv_vsetpvfn" هو نظير لـ "vsprintf"، ولكنه يسمح لك بتحديد إما مؤشر
إلى قائمة وسائط متغيرة أو عنوان وطول مجموعة من SVs. الاخير
تشير الحجة إلى قيمة منطقية؛ عند العودة، إذا كان هذا المنطق منطقيًا، فهو خاص بالإعدادات المحلية
تم استخدام المعلومات لتنسيق السلسلة، وبالتالي فإن محتويات السلسلة هي
غير جدير بالثقة (انظر بيرلسيك). قد يكون هذا المؤشر فارغًا إذا لم تكن هذه المعلومات كذلك
مهم. لاحظ أن هذه الوظيفة تتطلب منك تحديد طول التنسيق.

وظائف "sv_set*()" ليست عامة بما يكفي للعمل على القيم التي تحتوي على "سحر".
راجع "الجداول الافتراضية السحرية" لاحقًا في هذا المستند.

يجب إنهاء كافة ملفات SV التي تحتوي على سلاسل بحرف "NUL". إذا لم يكن
تم إنهاء "NUL" - هناك خطر حدوث عمليات تفريغ أساسية وفساد من التعليمات البرمجية التي تمرر ملف
سلسلة إلى وظائف C أو استدعاءات النظام التي تتوقع سلسلة منتهية بـ "NUL". بيرل الخاصة
عادةً ما تضيف الوظائف "NUL" زائدة لهذا السبب. ومع ذلك، يجب أن تكون كذلك
كن حذرًا جدًا عند تمرير سلسلة مخزنة في SV إلى دالة C أو استدعاء النظام.

للوصول إلى القيمة الفعلية التي يشير إليها SV، يمكنك استخدام وحدات الماكرو:

سفيف(سف*)
SvUV(SV*)
سفنف(سف*)
SvPV(SV*، لون STRLEN)
SvPV_nolen(SV*)

والتي سوف تجبر تلقائيًا النوع العددي الفعلي على IV أو UV أو مزدوج أو سلسلة.

في الماكرو "SvPV"، يتم وضع طول السلسلة التي تم إرجاعها في المتغير "len"
(هذا ماكرو، لذلك عليك أن تفعل ذلك ليست استخدم &لين). إذا كنت لا تهتم ما هو طول البيانات
هو استخدام الماكرو "SvPV_nolen". تاريخيًا، الماكرو "SvPV" مع المتغير العام
تم استخدام "PL_na" في هذه الحالة. ولكن هذا يمكن أن يكون غير فعال تمامًا لأن "PL_na"
يجب الوصول إليها في وحدة تخزين مؤشر الترابط المحلية في لغة Perl المترابطة. وعلى أية حال، تذكر ذلك
يسمح Perl بسلاسل عشوائية من البيانات التي قد تحتوي على NULs وقد لا تحتوي عليها
تم إنهاؤه بواسطة "NUL".

تذكر أيضًا أن لغة C لا تسمح لك بقول "foo(SvPV(s, len), len); بأمان". قد يكون
العمل مع المترجم الخاص بك، لكنه لن يعمل مع الجميع. كسر هذا النوع من البيان
في مهام منفصلة:

SV *s;
سترلين لين؛
شار *ptr;
ptr = SvPV(s, len);
foo(ptr, len);

إذا كنت تريد معرفة ما إذا كانت القيمة العددية صحيحة، فيمكنك استخدام:

SvTRUE(SV*)

على الرغم من أن لغة Perl ستقوم تلقائيًا بإنشاء سلاسل لك، إلا أنه إذا كنت بحاجة إلى إجبار لغة Perl على ذلك
تخصيص المزيد من الذاكرة لSV الخاص بك، يمكنك استخدام الماكرو

SvGROW (SV*، STRLEN newlen)

والتي ستحدد ما إذا كان هناك حاجة إلى تخصيص المزيد من الذاكرة. إذا كان الأمر كذلك، فإنه سيتم استدعاء
وظيفة "sv_grow". لاحظ أن "SvGROW" يمكنه فقط زيادة المخصصات وليس تقليلها
ذاكرة SV وأنها لا تضيف تلقائيًا مساحة للبايت "NUL" الزائد
(عادةً ما تقوم وظائف السلسلة الخاصة بـ Perl بـ "SvGROW(sv, len + 1)").

إذا كنت تريد الكتابة إلى مخزن مؤقت لـ SV موجود وتعيين قيمته على سلسلة، فاستخدم
SvPV_force() أو أحد متغيراته لإجبار SV على أن يكون كهروضوئيًا. سيؤدي هذا إلى إزالة أي من
أنواع مختلفة من عدم الشدة من SV مع الحفاظ على محتوى SV في
الكهروضوئية. يمكن استخدام هذا، على سبيل المثال، لإلحاق البيانات من دالة API إلى المخزن المؤقت
بدون نسخ إضافي:

(باطل)SvPVbyte_force(sv, len);
s = SvGROW(sv, len + Needlen + 1);
/* شيء يعدل ما يصل إلى بايتات إبرة في s+len، ولكن
يعدل البايتات الجديدة
على سبيل المثال. newlen = read(fd, s + len, Needlen);
تجاهل الأخطاء لهذه الأمثلة
*/
s[len + newlen] = '\0';
SvCUR_set(sv, len + newlen);
SvUTF8_off(sv);
SvSETMAGIC(sv);

إذا كانت لديك بالفعل البيانات في الذاكرة أو إذا كنت تريد إبقاء التعليمات البرمجية الخاصة بك بسيطة، فيمكنك ذلك
استخدم أحد متغيرات sv_cat*()، مثل sv_catpvn(). إذا كنت تريد إدراجها في أي مكان
السلسلة التي يمكنك استخدامها sv_insert() or sv_insert_flags().

إذا لم تكن بحاجة إلى المحتوى الحالي لـ SV، فيمكنك تجنب بعض النسخ باستخدام:

sv_setpvn(sv, ""، 0);
s = SvGROW(sv, Needlen + 1);
/* شيء يعدل ما يصل إلى بايتات إبرة في s، ولكنه يعدل
نيولن بايت
على سبيل المثال. newlen = read(fd, s.needlen);
*/
s[newlen] = '\0';
SvCUR_set(sv, newlen);
SvPOK_only(sv); /* يقوم أيضًا بمسح SVf_UTF8 */
SvSETMAGIC(sv);

مرة أخرى، إذا كان لديك بالفعل البيانات في الذاكرة أو كنت ترغب في تجنب تعقيد الملف
أعلاه، يمكنك استخدام sv_setpvn().

إذا كان لديك مخزن مؤقت مخصص مع نيو اكس () وتريد تعيين ذلك كقيمة SV، يمكنك ذلك
تستخدم sv_usepvn_flags(). يحتوي هذا على بعض المتطلبات إذا كنت تريد تجنب إعادة تخصيص Perl
المخزن المؤقت ليناسب NUL الزائدة:

Newx(buf, somesize+1, char);
/* ... املأ الفراغ ... */
buf[somesize] = '\0';
sv_usepvn_flags(sv, buf, somesize, SV_SMAGIC | SV_HAS_TRAILING_NUL);
/* buf ينتمي الآن إلى Perl، لا تحرره */

إذا كان لديك ملف SV وتريد معرفة نوع البيانات التي يعتقد Perl أنها مخزنة فيه، فيمكنك ذلك
استخدم وحدات الماكرو التالية للتحقق من نوع SV لديك.

سفيوك(SV*)
سفنوك(SV*)
سفبوك (SV*)

يمكنك الحصول على الطول الحالي للسلسلة المخزنة في SV وتعيينه بما يلي
وحدات الماكرو:

سفكيور(SV*)
SvCUR_set(SV*, I32 فال)

يمكنك أيضًا الحصول على مؤشر إلى نهاية السلسلة المخزنة في ملف SV باستخدام الماكرو:

سفيند(SV*)

لكن لاحظ أن وحدات الماكرو الثلاثة الأخيرة هذه صالحة فقط إذا كانت "SvPOK()" صحيحة.

إذا كنت تريد إلحاق شيء ما بنهاية السلسلة المخزنة في "SV*"، فيمكنك استخدام ملف
الوظائف التالية:

void sv_catpv(SV*, const char*);
void sv_catpvn(SV*, const char*, STRLEN);
void sv_catpvf(SV*, const char*, ...);
باطلة sv_vcatpvfn(SV*, const char*, STRLEN, va_list *, SV **,
I32، بول)؛
باطلة sv_catsv(SV*, SV*);

تحسب الوظيفة الأولى طول السلسلة المراد إلحاقها باستخدام "strlen".
وفي الحالة الثانية، تحدد طول السلسلة بنفسك. الوظيفة الثالثة
يعالج وسيطاته مثل "sprintf" ويلحق الإخراج المنسق. الرابع
تعمل الوظيفة مثل "vsprintf". يمكنك تحديد عنوان وطول مجموعة من SVs
بدلاً من الوسيطة va_list. تعمل الوظيفة الخامسة على توسيع السلسلة المخزنة في ملف
SV الأول مع السلسلة المخزنة في SV الثاني. كما أنه يفرض على SV الثاني أن يكون
يتم تفسيرها على أنها سلسلة.

وظائف "sv_cat*()" ليست عامة بما يكفي للعمل على القيم التي تحتوي على "سحر".
راجع "الجداول الافتراضية السحرية" لاحقًا في هذا المستند.

إذا كنت تعرف اسم المتغير العددي، فيمكنك الحصول على مؤشر إلى SV الخاص به باستخدام الملف
التالية:

SV* get_sv("package::varname", 0);

يؤدي هذا إلى إرجاع NULL إذا كان المتغير غير موجود.

إذا كنت تريد معرفة ما إذا كان هذا المتغير (أو أي SV آخر) "محددًا" بالفعل، فيمكنك ذلك
الاتصال على:

سفوك(SV*)

يتم تخزين القيمة العددية "undef" في مثيل SV يسمى "PL_sv_undef".

ويمكن استخدام عنوانه عند الحاجة إلى "SV*". تأكد من أنك لا تحاول ذلك
مقارنة sv عشوائي مع &PL_sv_undef. على سبيل المثال، عند التعامل مع كود Perl، سوف يعمل
بشكل صحيح ل:

foo(undef);

ولكنها لن تعمل عند استدعائها كـ:

$x = undef;
فو($x);

لذلك لتكرار الاستخدام دائمًا SvOK () للتحقق مما إذا تم تعريف sv.

يجب عليك أيضًا توخي الحذر عند استخدام &PL_sv_undef كقيمة في AVs أو HVs (راجع "AVs،
الجهد العالي والقيم غير المحددة").

هناك أيضًا القيمتان "PL_sv_yes" و"PL_sv_no"، اللتان تحتويان على القيمة المنطقية TRUE و
القيم FALSE، على التوالي. مثل "PL_sv_undef"، يمكن استخدام عناوينهم في أي وقت
"SV*" مطلوب.

لا تنخدع بالاعتقاد بأن "(SV *) 0" هو نفس &PL_sv_undef. خد هذا
رمز:

SV* sv = (SV*) 0;
إذا (سأقوم بإرجاع قيمة حقيقية) {
إس في = sv_2mortal(newSViv(42)) ؛
}
sv_setsv(ST(0)، سانت)؛

يحاول هذا الرمز إرجاع SV جديد (الذي يحتوي على القيمة 42) إذا كان يجب أن يُرجع ملف
القيمة الحقيقية، أو undef خلاف ذلك. بدلاً من ذلك، أعادت مؤشرًا فارغًا، في مكان ما
في المستقبل، سيؤدي إلى انتهاك التجزئة، أو خطأ في الناقل، أو مجرد نتائج غريبة.
قم بتغيير الصفر إلى &PL_sv_undef في السطر الأول وسيكون كل شيء على ما يرام.

لتحرير ملف SV قمت بإنشائه، اتصل بـ "SvREFCNT_dec(SV*)". عادة هذه المكالمة ليست كذلك
ضروري (انظر "التهم المرجعية والوفيات").

تعويضات
يوفر Perl الوظيفة "sv_chop" لإزالة الأحرف بكفاءة من البداية
من سلسلة؛ تعطيه SV ومؤشرًا إلى مكان ما داخل PV، ويتم تجاهله
كل شيء قبل المؤشر. تأتي الكفاءة عن طريق اختراق بسيط: بدلاً من ذلك
في الواقع، بعد إزالة الأحرف، يقوم "sv_chop" بتعيين العلامة "OOK" (الإزاحة OK) للإشارة إليها
الوظائف الأخرى التي يسري عليها اختراق الإزاحة هي تحريك المؤشر الكهروضوئي (يُسمى
"SvPVX") للأمام بمقدار عدد البايتات المقطوعة، ويضبط "SvCUR" و"SvLEN"
وفقاً لذلك. (يتم استخدام جزء من المساحة بين المؤشرات الكهروضوئية القديمة والجديدة للتخزين
عدد البايتات المقطعة.)

ومن ثم، في هذه المرحلة، فإن بداية المخزن المؤقت الذي خصصناه موجود في "SvPVX(sv) -"
SvIV(sv)" في الذاكرة ويشير المؤشر الكهروضوئي إلى منتصف هذا المخصص
تخزين.

وأفضل دليل على ذلك هو المثال. عادة النسخ عند الكتابة سيمنع
استبدال المشغل من استخدام هذا الاختراق، ولكن إذا كان بإمكانك صياغة سلسلة لها
النسخ عند الكتابة غير ممكن، يمكنك رؤيته أثناء اللعب. في التنفيذ الحالي،
يتم استخدام البايت النهائي للمخزن المؤقت للسلسلة كعدد مرجعي للنسخ عند الكتابة. إذا كان المخزن المؤقت
ليست كبيرة بما يكفي، فسيتم تخطي النسخ عند الكتابة. قم أولاً بإلقاء نظرة على سلسلة فارغة:

% ./perl -Ilib -MDevel::Peek -le '$a=""; $a .= ""; تفريغ $a'
إس في = PV(0x7ffb7c008a70) at 0x7ffb7c030390
ريفكنت = 1
FLAGS = (POK ، pPOK)
PV = 0x7ffb7bc05b50 ""\0
العملة = 0
لين = 10

لاحظ هنا أن LEN هو 10. (قد يختلف باختلاف النظام الأساسي الخاص بك.) قم بتمديد طول
سلسلة إلى واحد أقل من 10، وقم بالاستبدال:

% ./perl -Ilib -MDevel::Peek -le '$a=""; $a.="123456789"; $a=~s/.//; تفريغ($a)'
إس في = PV(0x7ffa04008a70) at 0x7ffa04030390
ريفكنت = 1
الأعلام = (POK، OOK، pPOK)
تعويض = 1
PV = 0x7ffa03c05b61 ( "\1" . ) "23456789"\0
العملة = 8
لين = 9

هنا يظهر عدد البايتات المقطوعة (1) بعد ذلك باسم OFFSET. الجزء من
تظهر السلسلة بين البدايات "الحقيقية" و"المزيفة" بين قوسين، وتظهر السلسلة
تعكس قيم "SvCUR" و"SvLEN" البداية المزيفة، وليست الحقيقية. (الأول
تصادف أن حرف المخزن المؤقت للسلسلة قد تغير إلى "\1" هنا، وليس "1"، لأن
يقوم التنفيذ الحالي بتخزين عدد الإزاحة في المخزن المؤقت للسلسلة. هذا يخضع ل
يتغير.)

يتم تنفيذ شيء مشابه لاختراق الأوفست على AVs لتمكين النقل الفعال و
الربط من بداية المصفوفة؛ بينما يشير "AvARRAY" إلى العنصر الأول في
المصفوفة المرئية من Perl، يشير "AvALLOC" إلى البداية الحقيقية لمصفوفة C.
عادة ما تكون هذه هي نفسها، ولكن يمكن إجراء عملية "التحويل" عن طريق الزيادة
"AvARRAY" بمقدار واحد وتقليل "AvFILL" و"AvMAX". مرة أخرى، الموقع الحقيقي
يتم تشغيل بداية المصفوفة C فقط عند تحرير المصفوفة. راجع "av_shift" في av.c.

ما هو حقا تخزين in an SV؟
تذكر أن الطريقة المعتادة لتحديد نوع العددية لديك هي استخدام "Sv*OK"
وحدات الماكرو. نظرًا لأن العدد العددي يمكن أن يكون رقمًا وسلسلة، فعادةً ما تكون وحدات الماكرو هذه كذلك
تُرجع دائمًا TRUE وسيؤدي استدعاء وحدات الماكرو "Sv*V" إلى إجراء التحويل المناسب لـ
سلسلة إلى عدد صحيح/مزدوج أو عدد صحيح/مزدوج إلى سلسلة.

إذا كنت في الحقيقة بحاجة إلى معرفة ما إذا كان لديك مؤشر عدد صحيح أو مزدوج أو سلسلة في SV، فأنت
يمكن استخدام وحدات الماكرو الثلاثة التالية بدلاً من ذلك:

SvIOKp(SV*)
SvNOKp(SV*)
سفبوكب(SV*)

ستخبرك هذه إذا كان لديك بالفعل مؤشر صحيح أو مزدوج أو سلسلة مخزنة في ملفك
SV. يشير الحرف "p" إلى القطاع الخاص.

هناك طرق مختلفة قد تختلف بها الأعلام الخاصة والعامة. على سبيل المثال، في
قد يكون لـ Perl 5.16 والإصدارات الأقدم من SV المقيدة قيمة أساسية صالحة في الفتحة IV (وبالتالي
SvIOKp صحيح)، ولكن يجب الوصول إلى البيانات عبر روتين FETCH بدلاً من
مباشرة، لذا فإن SvIOK غير صحيح. (في بيرل 5.18 وما بعده، تستخدم الكميات القياسية المربوطة الأعلام نفسها
طريقة أخرى مثل الكميات غير المقيدة.) والسبب الآخر هو عند حدوث تحويل رقمي ودقة
تم فقدانه: يتم تعيين العلامة الخاصة فقط على قيم "الخسارة". لذلك عندما يتم تحويل NV إلى
سيتم تعيين IV مع الخسارة، وSvIOKp، وSvNOKp، وSvNOK، بينما لن يتم تعيين SvIOK.

بشكل عام، على الرغم من ذلك، فمن الأفضل استخدام وحدات الماكرو "Sv*V".

العمل مع مركبات
هناك طريقتان لإنشاء وتحميل AV. الطريقة الأولى تقوم بإنشاء AV فارغ:

AV* newAV();

تقوم الطريقة الثانية بإنشاء AV وملؤه مبدئيًا بـ SVs:

AV* av_make(SSize_t num, SV **ptr);

تشير الوسيطة الثانية إلى مصفوفة تحتوي على "num" "SV*". بمجرد أن كان AV
تم إنشاؤها، ويمكن تدمير SVs، إذا رغبت في ذلك.

بمجرد إنشاء AV، تكون العمليات التالية ممكنة عليه:

باطلة av_push(AV*, SV*);
SV* av_pop(AV*);
SV* av_shift(AV*);
باطلة av_unshift(AV*, SSize_t num);

يجب أن تكون هذه العمليات مألوفة، باستثناء "av_unshift". هذا الروتين
يضيف عناصر "num" في مقدمة المصفوفة بقيمة "undef". يجب عليك بعد ذلك استخدام
"av_store" (الموصوف أدناه) لتعيين قيم لهذه العناصر الجديدة.

فيما يلي بعض الوظائف الأخرى:

SSize_t av_top_index(AV*);
SV** av_fetch(AV*, SSize_t key, I32 lval);
SV** av_store(AV*, SSize_t key, SV* val);

ترجع الدالة "av_top_index" أعلى قيمة فهرس في مصفوفة (تمامًا مثل $#array
في بيرل). إذا كانت المصفوفة فارغة، فسيتم إرجاع -1. تقوم الدالة "av_fetch" بإرجاع الملف
القيمة في الفهرس "key"، ولكن إذا كانت "lval" غير صفرية، فسيقوم "av_fetch" بتخزين قيمة undef
في ذلك المؤشر. تقوم وظيفة "av_store" بتخزين القيمة "val" في الفهرس "key"، وتقوم بذلك
عدم زيادة العدد المرجعي لـ "val". وبالتالي فإن المتصل هو المسؤول عن اتخاذ
اهتم بذلك، وإذا أعاد "av_store" القيمة NULL، فسيتعين على المتصل تقليل قيمة
عدد المراجع لتجنب تسرب الذاكرة. لاحظ أن كلاً من "av_fetch" و"av_store" يعودان
"SV**"، وليس "SV*" كقيمة الإرجاع الخاصة بها.

عدد قليل:

باطلة av_clear(AV*);
باطلة av_undef(AV*);
باطلة av_extend(AV*, SSize_t key);

تقوم الدالة "av_clear" بحذف كافة العناصر الموجودة في صفيف AV*، ولكنها لا تقوم بذلك فعليًا
حذف المصفوفة نفسها. ستقوم وظيفة "av_undef" بحذف كافة العناصر الموجودة في الملف
المصفوفة بالإضافة إلى المصفوفة نفسها. تقوم وظيفة "av_extend" بتوسيع المصفوفة بحيث تكون كذلك
يحتوي على عناصر "مفتاح+1" على الأقل. إذا كان "key+1" أقل من المخصص حاليًا
طول المصفوفة، ثم لا يتم فعل أي شيء.

إذا كنت تعرف اسم متغير الصفيف، فيمكنك الحصول على مؤشر إلى AV الخاص به باستخدام الملف
التالية:

AV* get_av("package::varname", 0);

يؤدي هذا إلى إرجاع NULL إذا كان المتغير غير موجود.

راجع "فهم سحر التجزئة والمصفوفات المرتبطة" لمزيد من المعلومات حول كيفية الاستخدام
وظائف الوصول إلى المصفوفة على المصفوفات المرتبطة.

العمل مع المركبات ذات الجهد العالي
لإنشاء HV، يمكنك استخدام الروتين التالي:

HV* newHV();

بمجرد إنشاء الجهد العالي، تكون العمليات التالية ممكنة عليه:

SV** hv_store(HV*, const char* key, U32 klen, SV* val, U32 hash);
SV** hv_fetch(HV*, const char* key, U32 klen, I32 lval);

المعلمة "klen" هي طول المفتاح الذي يتم تمريره (لاحظ أنه لا يمكنك تمرير 0
in كقيمة "klen" لإخبار Perl بقياس طول المفتاح). "فال"
تحتوي الوسيطة على مؤشر SV للعدد الذي يتم تخزينه، و"التجزئة" هي المحسوبة مسبقًا
قيمة التجزئة (صفر إذا كنت تريد "hv_store" أن يحسبها لك). المعلمة "لفال".
يشير إلى ما إذا كان هذا الجلب هو في الواقع جزء من عملية مخزن، وفي هذه الحالة جديد
ستتم إضافة قيمة غير محددة إلى HV باستخدام المفتاح المتوفر وسيعود "hv_fetch".
كما لو كانت القيمة موجودة بالفعل.

تذكر أن "hv_store" و"hv_fetch" يعرضان "SV**" وليس "SV*" فقط. للوصول إلى
القيمة العددية، يجب عليك أولاً إلغاء الإشارة إلى القيمة المرجعة. ومع ذلك، يجب عليك التحقق من ذلك
تأكد من أن القيمة المرجعة ليست فارغة قبل إلغاء مرجعيتها.

تتحقق أول هاتين الوظيفتين من وجود إدخال جدول التجزئة، والثانية
يحذفها.

bool hv_exists(HV*, const char* key, U32 klen);
SV* hv_delete(HV*, const char* key, U32 klen, I32 flags);

إذا كانت "العلامات" لا تتضمن علامة "G_DISCARD"، فسيقوم "hv_delete" بإنشاء وإرجاع
نسخة بشرية من القيمة المحذوفة.

والمزيد من الوظائف المتنوعة:

باطلة hv_clear(HV*);
باطلة hv_undef(HV*);

مثل نظيراتها من AV، يقوم "hv_clear" بحذف كافة الإدخالات الموجودة في جدول التجزئة ولكنه يفعل ذلك
لا يتم حذف جدول التجزئة فعليًا. يقوم "hv_undef" بحذف كل من الإدخالات والتجزئة
الجدول نفسه.

يحتفظ Perl بالبيانات الفعلية في قائمة مرتبطة من الهياكل مع typedef لـ HE. هؤلاء
تحتوي على المفتاح الفعلي ومؤشرات القيمة (بالإضافة إلى الحمل الإداري الإضافي). المفتاح
هو مؤشر سلسلة. القيمة هي "SV*". ومع ذلك، بمجرد حصولك على "HE*"، يمكنك الحصول على
المفتاح والقيمة الفعلية، استخدم الإجراءات المحددة أدناه.

I32 hv_iterinit(HV*);
/* إعداد نقطة البداية لاجتياز جدول التجزئة */
HE* hv_iternext(HV*);
/* احصل على الإدخال التالي وأرجع المؤشر إلى a
البنية التي تحتوي على المفتاح والقيمة */
char* hv_iterkey(HE* input, I32* retlen);
/* احصل على المفتاح من بنية HE ثم ارجعه أيضًا
طول السلسلة الرئيسية */
SV* hv_iterval(HV*, HE*entry);
/* إرجاع مؤشر SV إلى قيمة HE
بناء */
SV* hv_itternextsv(HV*, char** key, I32* retlen);
/* يجمع روتين الراحة هذا بين hv_iternext و
hv_iterkey، وhv_iterval. المفتاح و ريتلين
الحجج هي قيم الإرجاع للمفتاح و
طول. يتم إرجاع القيمة في الوسيطة SV* */

إذا كنت تعرف اسم متغير التجزئة، فيمكنك الحصول على مؤشر إلى القيمة العالية الخاصة به باستخدام الملف
التالية:

HV* get_hv("package::varname", 0);

يؤدي هذا إلى إرجاع NULL إذا كان المتغير غير موجود.

يتم تعريف خوارزمية التجزئة في الماكرو "PERL_HASH":

PERL_HASH(التجزئة، المفتاح، كلين)

يختلف التنفيذ الدقيق لهذا الماكرو حسب البنية وإصدار Perl، و
قد تتغير قيمة الإرجاع لكل استدعاء، وبالتالي فإن القيمة صالحة فقط لمدة a
عملية بيرل واحدة

راجع "فهم سحر التجزئة والمصفوفات المرتبطة" لمزيد من المعلومات حول كيفية الاستخدام
وظائف الوصول إلى التجزئة على التجزئة المرتبطة.

مزيج API ملحقات
بدءًا من الإصدار 5.004، يتم أيضًا دعم الوظائف التالية:

HE* hv_fetch_ent (HV* tb, SV* key, I32 lval, U32 hash);
HE* hv_store_ent (HV* tb, SV* key, SV* val, U32 hash);

bool hv_exists_ent (HV* tb, SV* key, U32 hash);
SV* hv_delete_ent (HV* tb، مفتاح SV*، علامات I32، تجزئة U32)؛

SV* hv_iterkeysv (إدخال HE*);

لاحظ أن هذه الوظائف تأخذ مفاتيح "SV*"، مما يبسط عملية كتابة رمز الامتداد
يتعامل مع هياكل التجزئة. تسمح هذه الوظائف أيضًا بتمرير مفاتيح "SV*" إلى "الربط"
وظائف دون إجبارك على تقييد المفاتيح (على عكس المجموعة السابقة من
المهام).

كما يقومون أيضًا بإرجاع وقبول إدخالات التجزئة الكاملة ("HE*")، مما يجعل استخدامها أكثر كفاءة
(نظرًا لأن رقم التجزئة لسلسلة معينة لا يلزم إعادة حسابه في كل مرة).
انظر بيرلابي للحصول على أوصاف مفصلة.

يجب دائمًا استخدام وحدات الماكرو التالية للوصول إلى محتويات إدخالات التجزئة. ملحوظة
أن الوسائط الخاصة بوحدات الماكرو هذه يجب أن تكون متغيرات بسيطة، حيث قد يتم تقييمها
أكثر من مرة. راجع perlapi للحصول على وصف تفصيلي لوحدات الماكرو هذه.

HePV (هو * هو، STRLEN لين)
هيفال (هو * هو)
هيهاش (هو * هو)
HeSVKEY(هو*هو)
HeSVKEY_force(HE* هو)
HeSVKEY_set(HE* هو، SV* sv)

تم تعريف هاتين الماكرو ذات المستوى الأدنى، لكن يجب استخدامهما فقط عند التعامل مع المفاتيح
التي ليست "SV*":

هيكي (هو * هو)
هيكلين (هو * هو)

لاحظ أن كلا من "hv_store" و"hv_store_ent" لا يزيدان العدد المرجعي لـ
المخزنة "فال"، وهي مسؤولية المتصل. إذا قامت هذه الوظائف بإرجاع NULL
القيمة، سيتعين على المتصل عادةً تقليل العدد المرجعي لـ "val" لتجنب حدوث خطأ
تسريب ذاكرة.

مركبات ذاتية الحركة، المركبات ذات الجهد العالي و غير محدد القيم
في بعض الأحيان يتعين عليك تخزين قيم غير محددة في AVs أو HVs. على الرغم من أن هذا قد يكون نادرا
الحالة، فإنه يمكن أن يكون خادعا. وذلك لأنك معتاد على استخدام &PL_sv_undef إذا كنت بحاجة إلى
SV غير محدد

على سبيل المثال، يخبرك الحدس أن رمز XS هذا:

AV *av = newAV();
av_store( av, 0, &PL_sv_undef );

يعادل كود بيرل هذا:

@av الخاص بي؛
$av[0] = undef;

لسوء الحظ، هذا ليس صحيحا. في الإصدار Perl 5.18 والإصدارات الأقدم، تستخدم AVs &PL_sv_undef كملف
علامة للإشارة إلى أنه لم تتم تهيئة عنصر الصفيف بعد. وهكذا "موجود
سيكون $av[0]" صحيحًا بالنسبة إلى كود Perl أعلاه، ولكنه خاطئ بالنسبة للمصفوفة التي تم إنشاؤها بواسطة XS
شفرة. في Perl 5.20، سيؤدي تخزين &PL_sv_undef إلى إنشاء عنصر للقراءة فقط، لأن
يتم تخزين العددية &PL_sv_undef نفسها، وليس نسخة.

يمكن أن تحدث مشكلات مماثلة عند تخزين &PL_sv_undef في المركبات عالية الجهد:

hv_store( hv, "key", 3, &PL_sv_undef, 0 );

سيؤدي هذا بالفعل إلى جعل القيمة "undef"، لكن إذا حاولت تعديل قيمة "key"،
سوف تحصل على الخطأ التالي:

تمت محاولة تعديل قيمة التجزئة غير القابلة للإنشاء

في الإصدار 5.8.0 من Perl، تم استخدام &PL_sv_undef أيضًا لوضع علامة على العناصر النائبة في التجزئة المقيدة. هذا
تسبب في عدم ظهور إدخالات التجزئة هذه عند التكرار فوق التجزئة أو عند التحقق منها
المفاتيح التي تحتوي على وظيفة "hv_exists".

يمكن أن تواجه مشكلات مماثلة عند تخزين &PL_sv_yes أو &PL_sv_no في AVs أو HVs.
ستؤدي محاولة تعديل هذه العناصر إلى ظهور الخطأ التالي:

تمت محاولة تعديل قيمة للقراءة فقط

لإختصار القصة الطويلة، يمكنك استخدام المتغيرات الخاصة &PL_sv_undef، &PL_sv_yes و
&PL_sv_no مع AVs وHVs، ولكن عليك التأكد من أنك تعرف ما تفعله.

بشكل عام، إذا كنت تريد تخزين قيمة غير محددة في AV أو HV، فلا يجب عليك استخدامها
&PL_sv_undef، بل قم بإنشاء قيمة جديدة غير محددة باستخدام وظيفة "newSV".
مثال:

av_store( أف، 42، newSV(0))؛
hv_store( hv، "foo"، 3، newSV(0)، 0)؛

مراجع حسابات
المراجع هي نوع خاص من العددية التي تشير إلى أنواع البيانات الأخرى (بما في ذلك أنواع البيانات الأخرى).
مراجع).

لإنشاء مرجع، استخدم إحدى الوظائف التالية:

SV* newRV_inc((SV*) شيء);
SV* newRV_noinc((SV*) شيء);

يمكن أن تكون الوسيطة "thing" أيًا من "SV*" أو "AV*" أو "HV*". الوظائف متطابقة
باستثناء أن "newRV_inc" يزيد العدد المرجعي لـ "الشيء"، بينما "newRV_noinc"
لا. لأسباب تاريخية، يعد "newRV" مرادفًا لـ "newRV_inc".

بمجرد حصولك على مرجع، يمكنك استخدام الماكرو التالي لإلغاء الإشارة إلى المرجع:

سفرف (سف*)

ثم قم باستدعاء الإجراءات المناسبة، وإرسال "SV*" الذي تم إرجاعه إلى "AV*" أو
"HV*"، إذا لزم الأمر.

لتحديد ما إذا كان SV مرجعًا، يمكنك استخدام الماكرو التالي:

سفيروك(SV*)

لاكتشاف نوع القيمة التي يشير إليها المرجع، استخدم الماكرو التالي ثم
تحقق من قيمة الإرجاع.

SvTYPE(SvRV(SV*))

الأنواع الأكثر فائدة التي سيتم إرجاعها هي:

<SVt_PVAV العددية
صفيف SVt_PVAV
تجزئة SVt_PVHV
رمز SVt_PVCV
SVt_PVGV Glob (ربما مؤشر ملف)

راجع "svtype" في perlapi لمزيد من التفاصيل.

مبارك مراجع حسابات و الفئه الأجسام
تُستخدم المراجع أيضًا لدعم البرمجة الموجهة للكائنات. في قاموس Perl's OO، an
الكائن هو مجرد مرجع تم مباركته في حزمة (أو فئة). مرة واحدة
مبارك، يمكن للمبرمج الآن استخدام المرجع للوصول إلى الأساليب المختلفة في ملف
فئة.

يمكن مباركة المرجع في حزمة تحتوي على الوظيفة التالية:

SV* sv_bless(SV* sv, HV* stash);

يجب أن تكون الوسيطة "sv" قيمة مرجعية. تحدد الوسيطة "stash" الفئة التي
المرجع سوف ينتمي إلى. راجع "Stashes and Globs" للحصول على معلومات حول تحويل الفصل
الأسماء في المخابئ.

/* ما يزال قيد الإنشاء */

تقوم الوظيفة التالية بترقية rv إلى مرجع إن لم يكن واحدًا بالفعل. يقوم بإنشاء SV جديد لـ
rv للإشارة إلى. إذا كان "اسم الفئة" غير فارغ، فسيتم مباركة SV في الفئة المحددة.
تم إرجاع SV.

SV* newSVrv(SV* rv, const char* classname);

تقوم الوظائف الثلاث التالية بنسخ عدد صحيح أو عدد صحيح غير موقّع أو مزدوج في ملف SV الذي
المرجع هو "رف". يتم مباركة SV إذا كان "اسم الفئة" غير فارغ.

SV* sv_setref_iv(SV* rv, const char* classname, IV iv);
SV* sv_setref_uv(SV* rv, const char* classname, UV uv);
SV* sv_setref_nv(SV* rv, const char* classname, NV iv);

تقوم الوظيفة التالية بنسخ قيمة المؤشر (القادم عنوان، ليست القادم خيط!) إلى SV
مرجعه هو rv. يتم مباركة SV إذا كان "اسم الفئة" غير فارغ.

SV* sv_setref_pv(SV* rv, const char* classname, void* pv);

تقوم الوظيفة التالية بنسخ سلسلة إلى ملف SV مرجعه "rv". اضبط الطول على
0 للسماح لـ Perl بحساب طول السلسلة. يتم مباركة SV إذا كان "اسم الفئة" غير فارغ.

SV* sv_setref_pvn(SV* rv, const char* classname, char* pv,
طول سترلين)؛

تختبر الوظيفة التالية ما إذا كان SV مباركًا في الفئة المحددة. نعم هو كذلك
عدم التحقق من علاقات الميراث.

int sv_isa(SV* sv, const char* name);

تختبر الوظيفة التالية ما إذا كان SV مرجعًا لكائن مبارك.

int sv_isobject(SV* sv);

تختبر الوظيفة التالية ما إذا كان SV مشتقًا من الفئة المحددة. يمكن لـ SV
يكون إما إشارة إلى كائن مبارك أو سلسلة تحتوي على اسم فئة. هذا هو
الوظيفة التي تنفذ وظيفة "UNIVERSAL::isa".

bool sv_derived_from(SV* sv, const char* name);

للتحقق مما إذا كان لديك كائن مشتق من فئة معينة عليك أن تكتب:

إذا (sv_isobject(sv) && sv_derived_from(sv, class)) { ... }

خلق جديد المتغيرات
لإنشاء متغير Perl جديد بقيمة undef يمكن الوصول إليه من Perl الخاص بك
البرنامج النصي، استخدم الإجراءات التالية، اعتمادًا على نوع المتغير.

SV* get_sv("package::varname", GV_ADD);
AV* get_av("package::varname", GV_ADD);
HV* get_hv("package::varname", GV_ADD);

لاحظ استخدام GV_ADD كمعلمة ثانية. يمكن الآن تعيين المتغير الجديد باستخدام
الإجراءات المناسبة لنوع البيانات.

هناك وحدات ماكرو إضافية قد تكون قيمها ذات مستوى بت أو يتم تعديلها باستخدام الوسيطة "GV_ADD".
لتمكين بعض الميزات الإضافية. تلك البتات هي:

GV_ADDMULTI
يضع علامة على المتغير على أنه محدد بالضرب، وبالتالي يمنع ما يلي:

اسم تستخدم مرة واحدة فقط: خطأ مطبعي محتمل

تحذير.

GV_ADDWARN
يصدر التحذير:

كان لا بد من خلق بشكل غير متوقع

إذا لم يكن المتغير موجودًا قبل استدعاء الدالة.

إذا لم تقم بتحديد اسم الحزمة، فسيتم إنشاء المتغير في الحزمة الحالية.

الرقم المرجعي التهم و معدل الوفيات
تستخدم لغة Perl آلية تجميع البيانات المهملة المرجعية المعتمدة على العد. SVs أو AVs أو HVs (xV لـ
باختصار فيما يلي) ابدأ حياتهم بعدد مرجعي قدره 1. إذا كان المرجع
ينخفض ​​عدد xV دائمًا إلى 0، ثم سيتم تدميره وتصبح ذاكرته متاحة
لإعادة الاستخدام.

لا يحدث هذا عادةً على مستوى Perl إلا إذا كان المتغير غير محدد أو الأخير
متغير يحمل إشارة إليه يتم تغييره أو الكتابة فوقه. وعلى المستوى الداخلي،
ومع ذلك، يمكن معالجة أعداد المراجع باستخدام وحدات الماكرو التالية:

int SvREFCNT(SV* sv);
SV* SvREFCNT_inc(SV* sv);
باطلة SvREFCNT_dec(SV* sv);

ومع ذلك، هناك وظيفة أخرى تتحكم في العدد المرجعي لها
دعوى. تتذكر أن وظيفة "newRV_inc" تقوم بإنشاء مرجع إلى المحدد
دعوى. كأثر جانبي، فإنه يزيد عدد مرجع الوسيطة. إذا لم يكن هذا
ما تريده، استخدم "newRV_noinc" بدلاً من ذلك.

على سبيل المثال، تخيل أنك تريد إرجاع مرجع من دالة XSUB. داخل
XSUB، يمكنك إنشاء SV الذي يحتوي في البداية على عدد مرجعي قدره واحد. ثُم أنت
اتصل بـ "newRV_inc"، وقم بتمريره إلى SV الذي تم إنشاؤه للتو. يؤدي هذا إلى إرجاع المرجع كـ SV جديد،
ولكن تمت زيادة العدد المرجعي لـ SV الذي قمت بتمريره إلى "newRV_inc" إلى اثنين.
الآن يمكنك إرجاع المرجع من روتين XSUB وتنسى أمر SV. لكن بيرل
لم يفعل ذلك! كلما تم إتلاف المرجع الذي تم إرجاعه، يتم حساب عدد المرجع الأصلي
يتم تقليل SV إلى واحد ولا يحدث شيء. سوف تتسكع سيارة SV دون أي وسيلة لذلك
الوصول إليه حتى ينتهي Perl نفسه. هذا تسرب للذاكرة.

الإجراء الصحيح إذن هو استخدام "newRV_noinc" بدلاً من "newRV_inc". ثم إذا و
عندما يتم تدمير المرجع الأخير، فإن العدد المرجعي لـ SV سيصل إلى الصفر
سيتم تدميرها، وإيقاف أي تسرب للذاكرة.

هناك بعض الوظائف المريحة المتاحة التي يمكن أن تساعد في تدمير xVs.
تقدم هذه الوظائف مفهوم "الوفيات". لقد كان للـ xV المميت وجوده
تم وضع علامة على العدد المرجعي ليتم تخفيضه، ولكن لم يتم تقليله فعليًا، حتى "قصيرة
"بعد وقت لاحق". بشكل عام، يعني مصطلح "بعد وقت قصير" عبارة Perl واحدة، مثل
استدعاء دالة XSUB. المحدد الفعلي للوقت الذي يكون فيه الموتى xV موجودين
يعتمد انخفاض عدد المراجع على وحدتي ماكرو، SAVETMPS وFreeTMPS. انظر بيرلكال
وperlxs لمزيد من التفاصيل حول وحدات الماكرو هذه.

"الإماتة" إذن هي في أبسط صورها "SvREFCNT_dec" مؤجلة. ومع ذلك، إذا كنت
إذا قمت بقتل متغير مرتين، فسيتم تقليل عدد المراجع مرتين لاحقًا.

يتم استخدام SVs "Mortal" بشكل أساسي لـ SVs الموضوعة على مكدس Perl. على سبيل المثال SV
الذي تم إنشاؤه فقط لتمرير رقم إلى فرعي يسمى يصبح مميتًا لتنظيفه
تلقائيًا عندما يتم إخراجه من المكدس. وبالمثل، يتم إرجاع النتائج بواسطة XSUBs
(التي يتم دفعها على المكدس) غالبًا ما تصبح مميتة.

لإنشاء متغير بشري، استخدم الوظائف:

SV* sv_newmortal()
SV* sv_2mortal(SV*)
SV* sv_mortalcopy(SV*)

يقوم الاستدعاء الأول بإنشاء SV بشري (بدون قيمة)، ويقوم الثاني بتحويل SV موجود إلى
SV بشري (وبالتالي يؤجل استدعاء "SvREFCNT_dec")، والثالث ينشئ بشريًا
نسخة من SV الموجودة. نظرًا لأن "sv_newmortal" لا يعطي قيمة لـ SV الجديد، فيجب عليه ذلك
عادةً ما يتم إعطاؤه واحدًا عبر "sv_setpv" و"sv_setiv" وما إلى ذلك:

SV *tmp = sv_newmortal();
sv_setiv(tmp, an_integer);

نظرًا لأن هذه عبارة عن عبارات C متعددة، فهي شائعة جدًا، لذا راجع هذا المصطلح بدلاً من ذلك:

SV *tmp = sv_2mortal(newSViv(an_integer));

يجب أن تكون حذرًا بشأن إنشاء متغيرات مميتة. أشياء غريبة يمكن أن تحدث إذا كنت
جعل نفس القيمة فانية ضمن سياقات متعددة، أو إذا جعلت متغيرا فانيا
عدة مرات. التفكير في "الإماتة" على أنها "SvREFCNT_dec" مؤجلة يجب أن يساعد في ذلك
التقليل من مثل هذه المشاكل. على سبيل المثال، إذا كنت تمر عبر SV فأنت علم لديه ارتفاع
ما يكفي من REFCNT للبقاء على قيد الحياة بعد استخدامه على المكدس، لا تحتاج إلى القيام بأي عملية إماتة. اذا أنت
لست متأكدًا، إذن فإن إجراء "SvREFCNT_inc" و"sv_2mortal"، أو إنشاء "sv_mortalcopy" هو
أكثر أمانًا.

إن الإجراءات المميتة ليست مخصصة فقط للـSVs؛ يمكن أن تصبح AVs وHVs مميتة عن طريق تمريرها
العنوان (النوع المُرسل إلى "SV*") إلى إجراءات "sv_2mortal" أو "sv_mortalcopy".

يخبأ و جلوبس
A خبأ عبارة عن تجزئة تحتوي على كافة المتغيرات التي تم تعريفها داخل الحزمة. كل مفتاح
المخبأ هو اسم رمز (مشترك بين جميع أنواع الكائنات المختلفة التي لها الامتداد
نفس الاسم)، وكل قيمة في جدول التجزئة هي GV (قيمة الكرة الأرضية). هذه الأصوات العالمية بدورها
يحتوي على إشارات إلى كائنات مختلفة بهذا الاسم، بما في ذلك (على سبيل المثال لا الحصر)
ما يلي:

القيمة العددية
قيمة الصفيف
قيمة التجزئة
مقبض الإدخال/الإخراج
شكل
روتين

يوجد مخبأ واحد يسمى "PL_defstash" يحتفظ بالعناصر الموجودة في "الرئيسي"
طَرد. للوصول إلى العناصر الموجودة في الحزم الأخرى، قم بإلحاق السلسلة "::" بالحزمة
اسم. العناصر الموجودة في حزمة "Foo" موجودة في المخبأ "Foo::" في PL_defstash. العناصر
الموجودة في حزمة "Bar::Baz" موجودة في مخبأ "Baz::" في مخبأ "Bar::".

للحصول على مؤشر التخزين لحزمة معينة، استخدم الوظيفة:

HV * gv_stashpv (اسم حرف * * ، أعلام I32)
HV* gv_stashsv(SV*، أعلام I32)

تأخذ الوظيفة الأولى سلسلة حرفية، وتستخدم الثانية السلسلة المخزنة في SV.
تذكر أن المخبأ هو مجرد جدول تجزئة، لذا يمكنك الحصول على "HV*". العلم "الأعلام".
سيقوم بإنشاء حزمة جديدة إذا تم ضبطها على GV_ADD.

الاسم الذي يريده "gv_stash*v" هو اسم الحزمة التي تريد جدول الرموز الخاص بها.
الحزمة الافتراضية تسمى "الرئيسية". إذا كان لديك حزم متداخلة متعددة، فقم بتمريرها
الأسماء إلى "gv_stash*v"، مفصولة بـ "::" كما في لغة Perl نفسها.

بدلاً من ذلك، إذا كان لديك SV مرجعًا مباركًا، فيمكنك اكتشاف المخبأ
المؤشر باستخدام:

HV* SvSTASH(SvRV(SV*));

ثم استخدم ما يلي للحصول على اسم الحزمة نفسها:

char* HvNAME(HV* stash);

إذا كنت بحاجة إلى مباركة كائن ما أو إعادة مباركته، يمكنك استخدام الوظيفة التالية:

SV* sv_bless(SV*، HV* مخبأ)

حيث يجب أن تكون الوسيطة الأولى، "SV*"، مرجعًا، والوسيطة الثانية هي a
خبأ. يمكن الآن استخدام "SV*" الذي تم إرجاعه بنفس طريقة استخدام أي ملف SV آخر.

لمزيد من المعلومات حول المراجع والبركات، راجع perlref.

مزدوج الكتابة SVS
تحتوي المتغيرات العددية عادة على نوع واحد فقط من القيمة، أو عدد صحيح، أو مزدوج، أو مؤشر، أو
مرجع. سيقوم Perl تلقائيًا بتحويل البيانات العددية الفعلية من النوع المخزن
في النوع المطلوب

تحتوي بعض المتغيرات العددية على أكثر من نوع واحد من البيانات العددية. على سبيل المثال،
متغير $! يحتوي إما على القيمة الرقمية لـ "errno" أو السلسلة المكافئة لها من
إما "strerror" أو "sys_errlist[]".

لفرض قيم بيانات متعددة في SV، يجب عليك القيام بأمرين: استخدام "sv_set*v"
إجراءات لإضافة النوع العددي الإضافي، ثم قم بتعيين علامة حتى يصدقها بيرل
تحتوي على أكثر من نوع واحد من البيانات. وحدات الماكرو الأربعة لتعيين العلامات هي:

SvIOK_on
SvNOK_on
SvPOK_on
SvROK_on

يعتمد الماكرو المحدد الذي يجب عليك استخدامه على روتين "sv_set*v" الذي قمت باستدعاءه أولاً.
وذلك لأن كل روتين "sv_set*v" يقوم بتشغيل البت الخاص بنوع معين فقط
يتم تعيين البيانات، ويطفئ كل ما تبقى.

على سبيل المثال، لإنشاء متغير Perl جديد يسمى "dberror" والذي يحتوي على كل من القيم الرقمية
وقيم خطأ السلسلة الوصفية، يمكنك استخدام الكود التالي:

خطأ داخلي خارجي ؛
شار خارجي *dberror_list;

SV* sv = get_sv("dberror", GV_ADD);
sv_setiv(sv, (IV) dberror);
sv_setpv(sv, dberror_list[dberror]);
SvIOK_on(sv);

إذا تم عكس ترتيب "sv_setiv" و"sv_setpv"، فإن الماكرو "SvPOK_on"
يجب أن يتم استدعاؤها بدلاً من "SvIOK_on".

للقراءة فقط القيم
في Perl 5.16 والإصدارات الأقدم، شاركت خاصية النسخ عند الكتابة (راجع القسم التالي) بت إشارة مع
العددية للقراءة فقط. وبالتالي فإن الطريقة الوحيدة لاختبار ما إذا كان "sv_setsv"، وما إلى ذلك، ستؤدي إلى رفع ملف
الخطأ "تعديل قيمة للقراءة فقط" في تلك الإصدارات هو:

SvREADONLY(sv) && !SvIsCOW(sv)

ضمن Perl 5.18 والإصدارات الأحدث، ينطبق SvREADONLY فقط على متغيرات القراءة فقط، وتحت
5.20، يمكن أيضًا أن تكون الكميات القياسية للنسخ عند الكتابة للقراءة فقط، لذا فإن التحقق أعلاه غير صحيح. أنت
اريد فقط:

SvREADONLY(sv)

إذا كنت بحاجة إلى إجراء هذا التحقق بشكل متكرر، فحدد الماكرو الخاص بك على النحو التالي:

#إذا كان PERL_VERSION >= 18
# تعريف SvTRULYREADONLY(sv) SvREADONLY(sv)
#else
# تعريف SvTRULYREADONLY(sv) (SvREADONLY(sv) && !SvIsCOW(sv))
#endif

Copy on كتابة
تطبق لغة Perl آلية النسخ عند الكتابة (COW) للعدديات، حيث توجد نسخ السلسلة
لا يتم إجراؤها فورًا عند الطلب، ولكن يتم تأجيلها حتى يصبح ذلك ضروريًا بواسطة أحدهما أو الآخر
تغيير العددية الأخرى. هذا واضح في الغالب، ولكن يجب على المرء أن يحرص على عدم تعديله
المخازن المؤقتة للسلسلة التي تتم مشاركتها بواسطة ملفات SV متعددة.

يمكنك اختبار ما إذا كان SV يستخدم النسخ عند الكتابة باستخدام "SvIsCOW(sv)".

يمكنك إجبار SV على إنشاء نسخته الخاصة من المخزن المؤقت للسلسلة عن طريق الاتصال
"sv_force_normal(sv)" أو SvPV_force_nolen(sv).

إذا كنت تريد جعل SV يسقط المخزن المؤقت للسلسلة، فاستخدم "sv_force_normal_flags(sv,
SV_COW_DROP_PV)" أو ببساطة "sv_setsv(sv, NULL)".

كل هذه الوظائف سوف تتأرجح على الكميات القياسية للقراءة فقط (راجع القسم السابق للمزيد
على تلك).

لاختبار أن التعليمات البرمجية الخاصة بك تعمل بشكل صحيح ولا تقوم بتعديل المخازن المؤقتة لـ COW، على الأنظمة
ذلك الدعم mmap(2) (أي Unix) يمكنك تكوين لغة Perl باستخدامها
"-Accflags=-DPERL_DEBUG_READONLY_COW" وسوف يحول انتهاكات المخزن المؤقت إلى أعطال.
ستجده بطيئًا بشكل رائع، لذا قد ترغب في تخطي اختبارات Perl الخاصة.

سحر المتغيرات
[هذا القسم لا يزال قيد الإنشاء. تجاهل كل شيء هنا. نشر أي فواتير.
كل ما لا يحل فهو حرام ]

قد يكون أي ملف SV سحريًا، أي أنه يحتوي على ميزات خاصة لا تتوفر في ملف SV العادي.
يتم تخزين هذه الميزات في بنية SV في قائمة مرتبطة بـ "struct Magic"،
تم تعريفه على "MAGIC".

سحر البناء {
MAGIC* mg_moremagic;
MGVTBL* mg_virtual;
U16 mg_private;
شار mg_type;
U8 mg_flags؛
I32 ملغ_لين؛
SV* mg_obj;
شار* mg_ptr;
};

لاحظ أن هذا ساري المفعول اعتبارًا من مستوى التصحيح 0، ويمكن أن يتغير في أي وقت.

تعيين سحر
يضيف Perl السحر إلى SV باستخدام الدالة sv_magic:

void sv_magic(SV* sv, SV* obj, int how, const char* name, I32 namlen);

تعد الوسيطة "sv" مؤشرًا إلى SV لاكتساب ميزة سحرية جديدة.

إذا لم يكن "sv" سحريًا بالفعل، يستخدم Perl الماكرو "SvUPGRADE" لتحويل "sv" إلى الكتابة
"SVt_PVMG". ثم يستمر Perl بإضافة سحر جديد إلى بداية القائمة المرتبطة
من الميزات السحرية. يتم حذف أي إدخال سابق لنفس النوع من السحر. لاحظ أن
يمكن تجاوز هذا، ويمكن ربط مثيلات متعددة من نفس النوع من السحر
مع SV.

عادةً ما يتم استخدام الوسيطتين "name" و"namlen" لربط سلسلة بالسحر
اسم المتغير. يتم تخزين "namlen" في حقل "mg_len" وإذا لم يكن "name"
فارغة ثم يتم تخزين نسخة "savepvn" من "name" أو "name" نفسه في "mg_ptr"
الحقل، اعتمادًا على ما إذا كانت "namlen" أكبر من الصفر أو تساوي الصفر على التوالي.
في حالة خاصة، إذا كان "(name && namlen == HEf_SVKEY)" فمن المفترض أن يحتوي "name" على
"SV*" ويتم تخزينه كما هو مع زيادة REFCNT الخاصة به.

تستخدم الدالة sv_magic "كيفية" لتحديد ملفات "Magic Virtual" المحددة مسبقًا، إن وجدت
"يجب تعيين الجدول" إلى الحقل "mg_virtual". راجع "الجداول الافتراضية السحرية"
القسم أدناه. يتم أيضًا تخزين الوسيطة "كيف" في الحقل "mg_type". قيمة ال
يجب اختيار "كيف" من مجموعة وحدات الماكرو "PERL_MAGIC_foo" الموجودة في بيرل. لاحظ أن
قبل إضافة وحدات الماكرو هذه، كانت الأجزاء الداخلية من لغة Perl تستخدم القيم الحرفية للأحرف بشكل مباشر، لذلك
قد تصادف أحيانًا تعليمات برمجية أو وثائق قديمة تشير إلى سحر "U" بدلاً من ذلك
من "PERL_MAGIC_uvar" على سبيل المثال.

يتم تخزين الوسيطة "obj" في حقل "mg_obj" في بنية "MAGIC". إذا لم يكن
تمامًا مثل الوسيطة "sv"، يتم زيادة العدد المرجعي للكائن "obj". لو
فهو نفسه، أو إذا كانت وسيطة "كيف" هي "PERL_MAGIC_arylen"، أو إذا كانت فارغة
المؤشر، فسيتم تخزين "obj" فقط، دون زيادة عدد المرجع.

راجع أيضًا "sv_magicext" في perlapi للحصول على طريقة أكثر مرونة لإضافة السحر إلى SV.

هناك أيضًا وظيفة لإضافة السحر إلى "HV":

void hv_magic(HV *hv, GV *gv, int how);

وهذا ببساطة يستدعي "sv_magic" ويفرض وسيطة "gv" على "SV".

لإزالة السحر من SV، قم باستدعاء الدالة sv_unmagic:

int sv_unmagic(SV *sv, int type);

يجب أن تكون وسيطة "النوع" مساوية لقيمة "كيف" عند إنشاء "SV" في البداية
سحري.

ومع ذلك، لاحظ أن "sv_unmagic" يزيل كل السحر من "نوع" معين من "SV". لو
تريد إزالة سحر معين فقط من "النوع" استنادًا إلى الجدول الظاهري السحري، فاستخدمه
"sv_unmagicext" بدلاً من ذلك:

int sv_unmagicext(SV *sv, int type, MGVTBL *vtbl);

سحر افتراضي ترابيزات
يعد الحقل "mg_virtual" في بنية "MAGIC" بمثابة مؤشر إلى "MGVTBL"، وهو عبارة عن
هيكل المؤشرات الوظيفية ويرمز إلى "Magic Virtual Table" للتعامل مع مختلف
العمليات التي يمكن تطبيقها على هذا المتغير.

يحتوي "MGVTBL" على خمسة (أو في بعض الأحيان ثمانية) مؤشرات لأنواع الروتين التالية:

int (*svt_get)(SV* sv, MAGIC* mg);
int (*svt_set)(SV* sv, MAGIC* mg);
U32 (*svt_len)(SV* sv، MAGIC* mg)؛
int (*svt_clear)(SV* sv, MAGIC* mg);
int (*svt_free)(SV* sv, MAGIC* mg);

كثافة العمليات (*svt_copy)(SV *sv, MAGIC* mg, SV *nsv,
const char *name, I32 namlen);
int (*svt_dup)(MAGIC *mg, CLONE_PARAMS *param);
int (*svt_local)(SV *nsv, MAGIC *mg);

تم تعيين بنية MGVTBL هذه في وقت الترجمة بيرل ويوجد حاليًا 32 نوعًا.
تحتوي هذه الهياكل المختلفة على مؤشرات لمختلف الإجراءات التي تؤدي أداءً إضافيًا
الإجراءات اعتمادًا على الوظيفة التي يتم استدعاؤها.

مؤشر الوظيفة تم اتخاذ الإجراء
---------------- ------------
svt_get افعل شيئًا ما قبل أن تكون قيمة SV
استرجاعها.
svt_set افعل شيئًا ما بعد تعيين قيمة لـ SV.
svt_len تقرير عن طول SV.
svt_clear امسح ما يمثله SV.
svt_free حرر أي مساحة تخزين إضافية مرتبطة بـ SV.

نسخ svt_copy متغير سحري مرتبط بعنصر مرتبط
يقوم svt_dup بتكرار البنية السحرية أثناء استنساخ الخيط
svt_local نسخ السحر إلى القيمة المحلية أثناء "المحلي"

على سبيل المثال، بنية MGVTBL تسمى "vtbl_sv" (والتي تتوافق مع "mg_type" من
يحتوي "PERL_MAGIC_sv") على:

{ ماجيك_جيت، ماجيك_سيت، ماجيك_لين، 0، 0 }

وبالتالي، عندما يتم تحديد SV على أنه سحري ومن النوع "PERL_MAGIC_sv"، إذا تم الحصول على
يتم تنفيذ العملية، ويتم استدعاء الروتين "magic_get". جميع الروتينات المختلفة
لأن الأنواع السحرية المختلفة تبدأ بـ "magic_". ملاحظة: الإجراءات السحرية ليست كذلك
تعتبر جزءًا من Perl API، ولا يجوز تصديرها بواسطة مكتبة Perl.

الفتحات الثلاث الأخيرة هي إضافة حديثة، وهي كذلك بالنسبة للتوافق مع التعليمات البرمجية المصدرية
يتم التحقق منه فقط إذا تم تعيين إحدى العلامات الثلاثة MGf_COPY أو MGf_DUP أو MGf_LOCAL
mg_flags. هذا يعني أن معظم التعليمات البرمجية يمكنها الاستمرار في الإعلان عن vtable كقيمة مكونة من 5 عناصر.
تُستخدم هذه الثلاثة حاليًا حصريًا بواسطة رمز الترابط، وهي تخضع بدرجة عالية
للتغيير.

الأنواع الحالية من Magic Virtual Tables هي:

mg_type
(النمط القديم شار وماكرو) نوع MGVTBL من السحر
-------------------------- ------ -------------
\0 PERL_MAGIC_sv vtbl_sv متغير عددي خاص
# طول صفيف PERL_MAGIC_arylen vtbl_arylen ($#ary)
% PERL_MAGIC_rhash (لا شيء) بيانات إضافية للمقيد
تجزئات
* PERL_MAGIC_debugvar vtbl_debugvar $DB::single، إشارة، تتبع
فار
. PERL_MAGIC_pos vtbl_pos pos() lvalue
: PERL_MAGIC_symtab (لا شيء) بيانات إضافية للرمز
الجداول
< PERL_MAGIC_backref vtbl_backref لبيانات المرجع الضعيفة
@ PERL_MAGIC_arylen_p (لا شيء) لنقل الأريلين من XPVAV
ب PERL_MAGIC_bm vtbl_regexp بوير-مور
(بحث سريع عن السلسلة)
c PERL_MAGIC_overload_table vtbl_ovrld يحمل جدول التحميل الزائد
(AMT) على المخبأ
D PERL_MAGIC_regdata vtbl_regdata يطابق Regex بيانات الموقع
(@+ و@- فار)
d PERL_MAGIC_regdatum vtbl_regdatum Regex يطابق بيانات الموقع
العنصر
تجزئة PERL_MAGIC_env vtbl_env %ENV
e PERL_MAGIC_envelem vtbl_envelem %ENV عنصر التجزئة
f PERL_MAGIC_fm vtbl_regexp سطر النموذج
(تنسيق "مجمع")
g PERL_MAGIC_regex_global vtbl_mglob m//g target
H PERL_MAGIC_hints vtbl_hints %^H تجزئة
h PERL_MAGIC_hintselem vtbl_hintselem %^H عنصر التجزئة
أنا PERL_MAGIC_isa vtbl_isa مجموعة @ISA
أنا PERL_MAGIC_isaelem vtbl_isaelem عنصر صفيف @ISA
ك PERL_MAGIC_nkeys vtbl_nkeys العددية (مفاتيح () lvalue
L PERL_MAGIC_dbfile (لا شيء) مصحح الأخطاء %_
l PERL_MAGIC_dbline vtbl_dbline مصحح الأخطاء %_
العنصر
N PERL_MAGIC_shared (لا شيء) تمت مشاركته بين المواضيع
n PERL_MAGIC_shared_scalar (لا شيء) مشترك بين المواضيع
o تحويل اللغة PERL_MAGIC_collxfrm vtbl_collxfrm
P PERL_MAGIC_tied vtbl_pack مصفوفة أو تجزئة مرتبطة
p PERL_MAGIC_tiedelem vtbl_packelem مصفوفة مرتبطة أو عنصر تجزئة
q PERL_MAGIC_tiedscalar vtbl_packelem عددي أو مقبض مقيد
r PERL_MAGIC_qr vtbl_regexp المترجمة مسبقًا qr// regex
S PERL_MAGIC_sig (لا شيء) تجزئة %SIG
PERL_MAGIC_sigelem vtbl_sigelem %SIG عنصر التجزئة
t PERL_MAGIC_taint vtbl_taint الملوث
U PERL_MAGIC_uvar vtbl_uvar متاح للاستخدام بواسطة
اضافات المتصفح
u PERL_MAGIC_uvar_elem (لا شيء) محجوز للاستخدام بواسطة
اضافات المتصفح
V PERL_MAGIC_vstring (none) كان SV عبارة عن سلسلة حرفية
v PERL_MAGIC_vec vtbl_vec vec() lvalue
w PERL_MAGIC_utf8 vtbl_utf8 معلومات UTF-8 المخزنة مؤقتًا
x PERL_MAGIC_substr vtbl_substr substr() lvalue
PERL_MAGIC_defelem vtbl_defelem مكرر الظل "foreach"
المعلمة المتغيرة / الذكية
التنشيط
\ PERL_MAGIC_lvref vtbl_lvref مرجع القيمة L
منشئ
] PERL_MAGIC_checkcall vtbl_checkcall تضمين/طفرة المكالمة
إلى هذه السيرة الذاتية
~ PERL_MAGIC_ext (لا شيء) متاح للاستخدام بواسطة
اضافات المتصفح

عند وجود حرف كبير وحرف صغير في الجدول، فالحرف الكبير
يُستخدم عادةً لتمثيل نوع ما من النوع المركب (قائمة أو تجزئة)، و
يتم استخدام الحرف الصغير لتمثيل عنصر من هذا النوع المركب. بعض الداخلية
يستخدم الكود علاقة الحالة هذه. ومع ذلك، فإن "v" و"V" (vec وv-string) موجودان
لا علاقة لها بأي حال من الأحوال.

تم تعريف النوعين السحريين "PERL_MAGIC_ext" و"PERL_MAGIC_uvar" خصيصًا للاستخدام بواسطة
الامتدادات ولن يتم استخدامها بواسطة Perl نفسه. يمكن للملحقات استخدام السحر "PERL_MAGIC_ext".
"إرفاق" معلومات خاصة بالمتغيرات (عادةً الكائنات). هذا خصوصا
مفيد لأنه لا توجد وسيلة لرمز بيرل العادي لإتلاف هذه المعلومات الخاصة
(على عكس استخدام عناصر إضافية لكائن التجزئة).

وبالمثل، يمكن استخدام السحر "PERL_MAGIC_uvar" بشكل مشابه رَابِطَة() لاستدعاء وظيفة C أي
الوقت الذي يتم فيه استخدام قيمة العددية أو تغييرها. يشير الحقل "mg_ptr" الخاص بـ "MAGIC" إلى أ
هيكل "ufuncs":

وظائف البنية {
I32 (*uf_val)(pTHX_ IV, SV*);
I32 (*uf_set)(pTHX_ IV, SV*);
IV uf_index;
};

عند قراءة SV أو الكتابة إليه، سيتم استدعاء الدالة "uf_val" أو "uf_set".
مع "uf_index" باعتباره الوسيط الأول ومؤشر إلى SV باعتباره الوسيط الثاني. مثال بسيط
كيفية إضافة السحر "PERL_MAGIC_uvar" موضح أدناه. لاحظ أن هيكل ufuncs هو
تم نسخه بواسطة sv_magic، حتى تتمكن من تخصيصه بأمان على المكدس.

باطل
أوماجيك (سف)
SV *SV;
قبل:
هيكل ufuncs uf;
CODE:
uf.uf_val = &my_get_fn;
uf.uf_set = &my_set_fn;
uf.uf_index = 0;
sv_magic(sv, 0, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf));

إرفاق "PERL_MAGIC_uvar" بالمصفوفات مسموح به ولكن ليس له أي تأثير.

بالنسبة للتجزئات، يوجد خطاف متخصص يمنح التحكم في مفاتيح التجزئة (ولكن ليس القيم).
يستدعي هذا الخطاف "PERL_MAGIC_uvar" "الحصول على" السحر إذا كانت وظيفة "set" في "ufuncs"
الهيكل فارغ. يتم تنشيط الخطاف عند الوصول إلى التجزئة باستخدام مفتاح
المحدد كـ "SV" من خلال الوظائف "hv_store_ent"، "hv_fetch_ent"،
"hv_delete_ent"، و"hv_exists_ent". الوصول إلى المفتاح كسلسلة من خلال الوظائف
بدون اللاحقة "..._ent" تلتف حول الخطاف. راجع "GUTS" في التجزئة::Util::FieldHash
للحصول على وصف مفصل.

لاحظ أنه نظرًا لأن الملحقات المتعددة قد تستخدم "PERL_MAGIC_ext" أو "PERL_MAGIC_uvar"
سحريًا، من المهم أن تأخذ الامتدادات عناية إضافية لتجنب التعارض. عادة
فقط باستخدام السحر على الكائنات المباركة في نفس فئة الامتداد
كافٍ. بالنسبة للسحر "PERL_MAGIC_ext"، من الجيد عادةً تعريف "MGVTBL"،
حتى لو كانت جميع حقولها 0، بحيث يمكن تحديد مؤشرات "MAGIC" الفردية على أنها
نوع معين من السحر باستخدام طاولتهم الافتراضية السحرية. يوفر "mg_findext" طريقة سهلة
طريقة للقيام بذلك:

STATIC MGVTBL my_vtbl = { 0, 0, 0, 0, 0, 0, 0, 0 };

ماجيك * ملغ؛
إذا ((mg = mg_findext(sv, PERL_MAGIC_ext, &my_vtbl))) {
/* هذا خاص بنا حقًا، وليس PERL_MAGIC_ext لوحدة أخرى */
my_priv_data_t *priv = (my_priv_data_t *)mg->mg_ptr;

}

لاحظ أيضًا أن الوظيفتين "sv_set*()" و"sv_cat*()" الموضحتين سابقًا تقومان بذلك ليست استدعاء
"ضبط" السحر على أهدافهم. يجب أن يتم ذلك من قبل المستخدم إما عن طريق الاتصال بالرقم
الماكرو "SvSETMAGIC()" بعد استدعاء هذه الوظائف، أو باستخدام أحد "sv_set*_mg()"
أو وظائف "sv_cat*_mg()". وبالمثل، يجب أن تقوم التعليمات البرمجية C العامة باستدعاء الماكرو "SvGETMAGIC()".
لاستدعاء أي سحر "get" إذا استخدموا SV تم الحصول عليه من مصادر خارجية في الوظائف
التي لا تتعامل مع السحر. انظر perlapi للحصول على وصف لهذه الوظائف. على سبيل المثال،
عادةً ما تحتاج الاستدعاءات إلى وظائف "sv_cat*()" إلى أن يتبعها "SvSETMAGIC()"، ولكن
لا يحتاجون إلى "SvGETMAGIC ()" سابق لأن تطبيقهم يتعامل مع سحر "الحصول على".

العثور على سحر
MAGIC *mg_find(SV *sv, int type); /* يجد المؤشر السحري لذلك
* يكتب */

يقوم هذا الروتين بإرجاع مؤشر إلى بنية "MAGIC" المخزنة في ملف SV. إذا كان SV يفعل ذلك
إذا لم يكن لديك هذه الميزة السحرية، فسيتم إرجاع "NULL". إذا كان لدى SV مثيلات متعددة لـ
تلك الميزة السحرية، سيتم إرجاع الميزة الأولى. يمكن استخدام "mg_findext" للعثور على ملف
هيكل "MAGIC" لـ SV يعتمد على نوعه السحري وجدوله الافتراضي السحري:

MAGIC *mg_findext(SV *sv, int type, MGVTBL *vtbl);

أيضًا، إذا كان SV الذي تم تمريره إلى "mg_find" أو "mg_findext" ليس من النوع SVt_PVMG، فقد يكون Perl أساسيًا
تفريغ.

int mg_copy(SV* sv, SV* nsv, const char* key, STRLEN klen);

يتحقق هذا الروتين لمعرفة أنواع السحر الذي يحتوي عليه "sv". إذا كان الحقل mg_type هو
حرف كبير، ثم يتم نسخ mg_obj إلى "nsv"، ولكن يتم تغيير الحقل mg_type إلى
يكون الحرف الصغير.

فهم القادم سحر of مربوط تجزئات و المصفوفات
التجزئة والمصفوفات المقيدة هي وحوش سحرية من النوع السحري "PERL_MAGIC_tied".

تحذير: اعتبارًا من الإصدار 5.004، سيتم الاستخدام الصحيح للمصفوفة ووظائف الوصول إلى التجزئة
يتطلب فهم بعض التحذيرات. بعض هذه التحذيرات تعتبر في الواقع أخطاء
في واجهة برمجة التطبيقات (API)، ليتم إصلاحها في الإصدارات اللاحقة، ويتم وضعها بين قوسين مع [MAYCHANGE] أدناه. لو
تجد نفسك بالفعل تطبق هذه المعلومات في هذا القسم، كن على علم بأن
قد يتغير السلوك في المستقبل، أم، دون سابق إنذار.

تربط وظيفة ربط Perl متغيرًا بكائن ينفذ المتغير
الحصول على، تعيين، الخ الأساليب. لأداء ما يعادل وظيفة ربط بيرل من XSUB،
يجب عليك تقليد هذا السلوك. ينفذ الكود أدناه الخطوات اللازمة - أولاً
يقوم بإنشاء تجزئة جديدة، ثم يقوم بإنشاء تجزئة ثانية يباركها في الفصل
والتي سوف تنفذ أساليب التعادل. وأخيرًا، يقوم بربط التجزئتين معًا، ثم يعود
إشارة إلى التجزئة المرتبطة الجديدة. لاحظ أن الكود أدناه لا يستدعي TIEHASH
الطريقة في فئة MyTie - راجع "استدعاء إجراءات Perl من داخل برامج C" للحصول على التفاصيل
على كيفية القيام بذلك.

SV *
mytie()
قبل:
HV * التجزئة؛
الجهد العالي * خبأ؛
SV * التعادل؛
CODE:
hash = newHV();
التعادل = newRV_noinc((SV*)newHV());
stash = gv_stashpv("MyTie", GV_ADD);
sv_bless(tie, stash);
hv_magic(hash, (GV*)tie, PERL_MAGIC_tied);
RETVAL = newRV_noinc(hash);
انتاج:
ريتفال

الدالة "av_store"، عند إعطائها وسيطة مصفوفة مرتبطة، تقوم فقط بنسخ سحر الملف
صفيف على القيمة المراد "تخزينها"، باستخدام "mg_copy". قد يُرجع أيضًا NULL، مشيرًا إلى ذلك
أن القيمة لا تحتاج فعليًا إلى تخزينها في المصفوفة. [قد يتغير] بعد المكالمة
إلى "av_store" في مصفوفة مرتبطة، سيحتاج المتصل عادةً إلى استدعاء "mg_set(val)" إلى
في الواقع استدعاء أسلوب "STORE" لمستوى Perl على كائن TIEARRAY. إذا فعل "av_store".
بإرجاع NULL، سيكون الاتصال بـ "SvREFCNT_dec(val)" ضروريًا أيضًا لتجنب حدوث خطأ
تسريب ذاكرة. [/ربما يتغير]

تنطبق الفقرة السابقة حرفيًا على الوصول إلى التجزئة المرتبطة باستخدام "hv_store" و
وظائف "hv_store_ent" أيضًا.

"av_fetch" ووظائف التجزئة المقابلة "hv_fetch" و"hv_fetch_ent" في الواقع
قم بإرجاع قيمة مميتة غير محددة تمت تهيئة سحرها باستخدام "mg_copy". ملحوظة
القيمة التي تم إرجاعها لا تحتاج إلى إلغاء تخصيصها، لأنها هالكة بالفعل.
[قد يتغير] ولكنك ستحتاج إلى استدعاء "mg_get()" على القيمة التي تم إرجاعها حتى تتمكن من ذلك
في الواقع استدعاء أسلوب "FETCH" لمستوى Perl على كائن TIE الأساسي. بصورة مماثلة،
يمكنك أيضًا استدعاء "mg_set()" على القيمة المرجعة بعد تعيين قيمة مناسبة
إليه باستخدام "sv_setsv"، والذي سيؤدي إلى استدعاء الأسلوب "STORE" على كائن TIE.
[/ربما يتغير]

[قد يتغير] بمعنى آخر، وظائف جلب/تخزين المصفوفة أو التجزئة لا تقوم حقًا بجلب و
تخزين القيم الفعلية في حالة المصفوفات والتجزئة المرتبطة. إنهم يسمون "mg_copy" فقط
إرفاق السحر بالقيم التي كان من المفترض أن يتم "تخزينها" أو "جلبها". يدعو في وقت لاحق ل
يقوم كل من "mg_get" و"mg_set" بالفعل بمهمة استدعاء أساليب TIE على الملف الأساسي
أشياء. وبالتالي فإن الآلية السحرية تنفذ حاليًا نوعًا من الوصول البطيء إلى المصفوفات
والتجزئة.

حاليًا (اعتبارًا من الإصدار 5.004 من Perl)، يتطلب استخدام وظائف الوصول إلى التجزئة والمصفوفة
يجب على المستخدم أن يكون على دراية بما إذا كان يعمل على التجزئة والمصفوفات "العادية" أم على
المتغيرات المرتبطة بها. قد يتم تغيير واجهة برمجة التطبيقات (API) لتوفير وصول أكثر شفافية لكليهما
أنواع البيانات المقيدة والعادية في الإصدارات المستقبلية. [/ربما يتغير]

من الأفضل أن تفهم أن واجهات TIEARRAY وTIEHASH هي مجرد سكر
استدعاء بعض استدعاءات أسلوب Perl أثناء استخدام صيغة التجزئة والصفيف الموحدة. استخدام
يفرض هذا السكر بعض النفقات العامة (عادةً حوالي اثنين إلى أربعة أكواد تشغيل إضافية لكل
عملية الجلب/التخزين، بالإضافة إلى إنشاء جميع المتغيرات البشرية المطلوبة
استدعاء الأساليب). سيكون هذا الحمل صغيرًا نسبيًا إذا كانت أساليب TIE كذلك
كبيرة في حد ذاتها، ولكن إذا كانت مجرد عبارات قليلة طويلة، فلن تكون النفقات العامة كذلك
تكون ضئيلة.

تعريب التغييرات
بيرل لديه بناء مفيد للغاية

{
محلي $var = 2;

}

هذا البناء ما يقرب من أي ما يعادل

{
$oldvar الخاص بي = $var;
$var = 2;

$var = $oldvar;
}

الفرق الأكبر هو أن البناء الأول سيعيد القيمة الأولية لـ
$var، بغض النظر عن كيفية خروج عنصر التحكم من الكتلة: "goto"، "return"، "die"/"eval"، وما إلى ذلك.
إنها أكثر كفاءة قليلاً أيضًا.

هناك طريقة لتحقيق مهمة مماثلة من لغة C عبر Perl API: إنشاء ملف كتلة زائفةو
قم بالترتيب للتراجع عن بعض التغييرات تلقائيًا في نهايتها، سواء كانت صريحة أو
عبر مخرج غير محلي (عبر يموت ()). ال منعيتم إنشاء البناء الشبيه بواسطة زوج من
وحدات الماكرو "إدخال"/"مغادرة" (راجع "إرجاع مقياس" في perlcall). قد يكون مثل هذا البناء
تم إنشاؤها خصيصًا لبعض المهام المترجمة المهمة، أو مهمة موجودة (مثل الحدود
يمكن استخدام روتين فرعي/كتلة متضمنة لـ Perl، أو زوج موجود لتحرير TMPs.
(في الحالة الثانية، يجب أن يكون الحمل الإضافي للتوطين الإضافي ضئيلًا تقريبًا.)
لاحظ أن أي XSUB يتم تضمينه تلقائيًا في زوج "ENTER"/"LEAVE".

داخل مثل هذا كتلة زائفة الخدمة التالية متاحة:

"حفظ (الكثافة i)"
"سافيف (الرابع ط)"
"SAVEI32(I32 ط)"
"سافيلونج (طويل ط)"
تقوم وحدات الماكرو هذه بترتيب الأشياء لاستعادة قيمة المتغير الصحيح "i" في النهاية
مرفق كتلة زائفة.

حفظ (ق)
سافيبتر (ع)
تقوم وحدات الماكرو هذه بترتيب الأشياء لاستعادة قيمة المؤشرات "s" و"p". "s" يجب أن يكون
مؤشر من النوع الذي ينجو من التحويل إلى "SV*" والعودة، يجب أن يكون "p" قادرًا على ذلك
التحويل المباشر إلى "char*" والعودة.

"حفظ حر(SV *sv)"
سيتم تقليل إعادة حساب "sv" في نهاية كتلة زائفة. هذا مشابه
إلى "sv_2mortal" حيث إنها أيضًا آلية لإجراء "SvREFCNT_dec" المؤجل.
ومع ذلك، في حين أن "sv_2mortal" يمتد عمر "sv" حتى بداية
العبارة التالية، "SAVEFREESV" تمددها حتى نهاية النطاق المرفق. هؤلاء
يمكن أن تكون الحياة مختلفة تمامًا.

قارن أيضًا "SAVEMORTALIZESV".

"حفظ الموتى (SV *sv)"
تمامًا مثل "SAVEFREESV"، ولكنه يُميت "sv" في نهاية النطاق الحالي بدلاً من
تقليل عدد المراجع الخاصة به. عادةً ما يكون لهذا تأثير في إبقاء "sv" على قيد الحياة
حتى ينتهي تنفيذ العبارة التي تسمى النطاق المباشر حاليًا.

"حفظ مجاني (OP *OP)"
"OP *" هو op_free()إد في نهاية كتلة زائفة.

سافيفريبف (ع)
قطعة الذاكرة التي يشار إليها بـ "p" هي آمن ()إد في نهاية مستعار-
منع.

"SAVECLEARSV(SV *sv)"
يمسح فتحة في لوحة المسودة الحالية والتي تتوافق مع "sv" في نهاية
كتلة زائفة.

"SAVEDELETE(HV *hv, char *key, I32 length)"
يتم حذف مفتاح "مفتاح" "hv" في نهاية كتلة زائفة. السلسلة المشار إليها بواسطة
"المفتاح" هو آمن ()إد. إذا كان لدى المرء مفتاح في تخزين قصير الأجل، المقابلة
يمكن إعادة تخصيص السلسلة على النحو التالي:

SAVEDELETE(PL_defstash, savepv(tmpbuf), strlen(tmpbuf));

"SAVEDESTRUCTOR(DESTRUCTORFUNC_NOCONTEXT_t f، void *p)"
في نهاية كتلة زائفة يتم استدعاء الدالة "f" باستخدام الوسيطة الوحيدة "p".

"SAVEDESTRUCTOR_X(DESTRUCTORFUNC_t f، void *p)"
في نهاية كتلة زائفة يتم استدعاء الدالة "f" مع السياق الضمني
الوسيطة (إن وجدت)، و"ص".

"SAVESTACK_POS ()"
تتم استعادة الإزاحة الحالية على المكدس الداخلي لـ Perl (راجع "SP") في نهاية
كتلة زائفة.

تحتوي قائمة واجهة برمجة التطبيقات (API) التالية على وظائف، وبالتالي يحتاج المرء إلى توفير مؤشرات إلى
بيانات قابلة للتعديل بشكل صريح (إما مؤشرات C، أو Perlish "GV *"s). حيث ما سبق
تأخذ وحدات الماكرو "int"، وتأخذ وظيفة مماثلة "int *".

"SV* save_scalar(GV *gv)"
أي ما يعادل رمز بيرل "gv $ المحلي".

"AV* save_ary(GV *gv)"
"HV* save_hash(GV *gv)"
يشبه "save_scalar"، لكن قم بترجمة @gv و%gv.

"" save_item (SV *item) باطل"
يكرر القيمة الحالية لـ "SV"، عند الخروج من "ENTER"/"LEAVE" الحالي
كتلة زائفة سيتم استعادة قيمة "SV" باستخدام القيمة المخزنة. لا يتعامل
سحر. استخدم "save_scalar" إذا تأثر السحر.

"void save_list(SV **sarg, I32 maxsarg)"
متغير من "save_item" الذي يأخذ وسائط متعددة عبر مصفوفة "sarg" من "SV*"
الطول "maxsarg".

"SV* save_svref(SV **sptr)"
يشبه "save_scalar"، ولكنه سيعيد "SV *".

"الفراغ save_aptr(AV **aptr)"
"" باطلة save_hptr(HV **hptr)"
يشبه "save_svref"، ولكن قم بترجمة "AV *" و"HV *".

تنفذ وحدة "الاسم المستعار" توطين الأنواع الأساسية داخل ملف المتصل نطاق.
يجب على الأشخاص المهتمين بكيفية توطين الأشياء في النطاق المحتوي أن يأخذوا
انظر هناك أيضًا.

روتينات


XSUBs و القادم حجة كومة
تعد آلية XSUB طريقة بسيطة لبرامج Perl للوصول إلى الإجراءات الفرعية للغة C. XSUB
سيكون للروتين مكدس يحتوي على الوسائط من برنامج Perl، وطريقة لذلك
خريطة من هياكل بيانات Perl إلى مكافئ C.

يمكن الوصول إلى وسيطات المكدس من خلال الماكرو ST(n) الذي يُرجع المكدس "n".
دعوى. الوسيطة 0 هي الوسيطة الأولى التي تم تمريرها في استدعاء الروتين الفرعي لـ Perl. هؤلاء
الوسيطات هي "SV*"، ويمكن استخدامها في أي مكان يتم فيه استخدام "SV*".

في معظم الأحيان، يمكن معالجة الإخراج من روتين C من خلال استخدام RETVAL و
توجيهات الإخراج. ومع ذلك، هناك بعض الحالات التي لا تكون فيها مكدس الوسيطة موجودًا بالفعل
طويلة بما يكفي للتعامل مع كافة قيم الإرجاع. مثال على ذلك هو POSIX تسنامي () الدعوة التي
لا يأخذ أي وسيطات، ولكنه يُرجع اثنين، التوقيت القياسي للمنطقة الزمنية المحلية والتوقيت الصيفي
الاختصارات.

للتعامل مع هذا الموقف، يتم استخدام توجيه PPCODE ويتم توسيع المكدس باستخدام
دقيق:

تمديد (SP، الأسطوانات)؛

حيث "SP" هو الماكرو الذي يمثل النسخة المحلية من مؤشر المكدس، و"num" هو
عدد العناصر التي يجب أن يتم تمديد المكدس بها.

الآن بعد أن أصبح هناك مكان في المكدس، يمكن دفع القيم عليه باستخدام الماكرو "PUSHs". ال
غالبًا ما تحتاج القيم المدفوعة إلى أن تكون "مميتة" (راجع "الأعداد المرجعية ومعدل الوفيات"):

الدفعات (sv_2mortal (newSViv (an_integer)))
الدفعات (sv_2mortal (newSVuv (an_unsigned_integer)))
الدفعات (sv_2mortal (newSVnv (a_double)))
PUSHs(sv_2mortal(newSVpv("بعض السلسلة"،0)))
/* على الرغم من أن المثال الأخير من الأفضل كتابته على أنه أكثر
* فعال: */
PUSHs(newSVpvs_flags("بعض السلسلة"، SVs_TEMP))

والآن يستدعي برنامج Perl "tzname"، وسيتم تعيين القيمتين كما في:

($standard_abbrev, $summer_abbrev) = POSIX::tzname;

هناك طريقة بديلة (وربما أبسط) لدفع القيم على المكدس وهي استخدام
دقيق:

وحدات XPUSH(SV*)

يقوم هذا الماكرو بضبط المكدس تلقائيًا، إذا لزم الأمر. وبالتالي، لا تحتاج إلى ذلك
استدعاء "تمديد" لتوسيع المكدس.

على الرغم من اقتراحاتهم في الإصدارات السابقة من هذا المستند، فإن وحدات الماكرو "(X)PUSH[iunp]"
. ليست مناسب لـ XSUBs التي تُرجع نتائج متعددة. من أجل ذلك، إما أن تتمسك بـ
وحدات الماكرو "(X)PUSHs" الموضحة أعلاه، أو استخدم وحدات الماكرو "m(X)PUSH[iunp]" الجديدة بدلاً من ذلك؛ يرى
“وضع قيمة C على مكدس Perl”.

لمزيد من المعلومات، راجع perlxs وperlxstut.

التحميل التلقائي مع XSUBs
إذا كان روتين التحميل التلقائي عبارة عن XSUB، كما هو الحال مع إجراءات Perl الفرعية، فإن Perl يضع الإجراء المؤهل بالكامل
اسم الروتين الفرعي الذي تم تحميله تلقائيًا في المتغير $AUTOLOAD الخاص بحزمة XSUB.

ولكنه يضع أيضًا نفس المعلومات في حقول معينة في XSUB نفسه:

HV *stash = CvSTASH(cv);
const char *subname = SvPVX(cv);
STRLEN name_length = SvCUR(cv); /* بالبايت */
U32 is_utf8 = SvUTF8(cv);

يحتوي "SvPVX(cv)" على الاسم الفرعي نفسه فقط، ولا يشمل الحزمة. للتحميل التلقائي
الروتينية في UNIVERSAL أو إحدى فئاتها الفائقة، "CvSTASH(cv)" تُرجع NULL أثناء
استدعاء الأسلوب على حزمة غير موجودة.

ملاحظات: توقف إعداد $AUTOLOAD عن العمل في الإصدار 5.6.1، والذي لم يدعم اشتراكات XS AUTOLOAD
على الاطلاق. قدم Perl 5.8.0 استخدام الحقول في XSUB نفسه. تمت استعادة بيرل 5.16.0
إعداد $AUTOLOAD. إذا كنت بحاجة إلى دعم 5.8-5.14، فاستخدم حقول XSUB.

دعوة بيرل إجراءات تبدأ من في غضون C البرامج
هناك أربعة إجراءات يمكن استخدامها لاستدعاء روتين فرعي لـ Perl من داخل لغة C
برنامج. هؤلاء الأربعة هم:

I32 call_sv(SV*, I32);
I32 call_pv(const char*, I32);
I32 call_method(const char*, I32);
I32 call_argv(const char*, I32, char**);

الروتين الأكثر استخدامًا هو "call_sv". تحتوي الوسيطة "SV*" إما على اسم
روتين Perl الفرعي الذي سيتم استدعاؤه، أو إشارة إلى الروتين الفرعي. الحجة الثانية
يتكون من أعلام تتحكم في السياق الذي يتم فيه استدعاء الروتين الفرعي، سواء كان ذلك أم لا
لا يتم تمرير الوسائط إلى الروتين الفرعي، وكيف ينبغي محاصرة الأخطاء، وكيف
علاج قيم الإرجاع.

تُرجع جميع الإجراءات الأربعة عدد الوسائط التي أرجعها الروتين الفرعي إلى لغة Perl
كومة.

كان يُطلق على هذه الإجراءات اسم "perl_call_sv"، وما إلى ذلك، قبل إصدار Perl v5.6.0، ولكن هذه الأسماء
تم إهمالها الآن؛ يتم توفير وحدات الماكرو التي تحمل الاسم نفسه للتوافق.

عند استخدام أي من هذه الإجراءات (باستثناء "call_argv")، يجب على المبرمج معالجة ملف
مكدس بيرل. وتشمل هذه وحدات الماكرو والوظائف التالية:

dSP
SP
علامة بوش()
ضعها بالخلف
سباجين
ENTER
حفظ
فريتمبس
غادر
XPUSH*()
بوب*()

للحصول على وصف تفصيلي لاصطلاحات الاتصال من C إلى Perl، راجع perlcall.

وضع a C قيمنا on بيرل كومة
تم وضع الكثير من أكواد التشغيل (هذه عملية أولية في آلة Perl Stack الداخلية).
SV* على المكدس. ومع ذلك، كتحسين، فإن SV المقابل (عادة) ليس كذلك
إعادة إنشائها في كل مرة. تعيد أكواد التشغيل استخدام ملفات SV المعينة خصيصًا (الهدفق) والتي هي (كما
نتيجة طبيعية) لا يتم تحريرها/إنشاءها باستمرار.

يتم إنشاء كل هدف مرة واحدة فقط (لكن راجع "اللوحات المؤقتة والتكرار" أدناه)، و
عندما يحتاج كود التشغيل إلى وضع عدد صحيح أو مزدوج أو سلسلة على المكدس، فإنه يقوم فقط بتعيين
الأجزاء المقابلة لها الهدف ويضع الهدف على المكدس.

الماكرو الذي سيتم وضع هذا الهدف على المكدس هو "PUSHTARG"، ويتم استخدامه مباشرة في البعض
أكواد التشغيل، وكذلك بشكل غير مباشر في الملايين من الآخرين، والتي تستخدمها عبر "(X)PUSH[iunp]".

نظرًا لإعادة استخدام الهدف، يجب عليك توخي الحذر عند دفع قيم متعددة على
كومة. الكود التالي لن يفعل ما تعتقده:

XPUSHi(10)
XPUSHi(20)

يُترجم هذا إلى "اضبط "TARG" على 10، وادفع المؤشر إلى "TARG" على المكدس؛ واضبط "TARG"
إلى 20، ادفع المؤشر إلى "TARG" على المكدس". في نهاية العملية، المكدس
لا يحتوي على القيمتين 10 و20، ولكنه يحتوي في الواقع على مؤشرين إلى "TARG"، وهما
لقد وضعنا على 20.

إذا كنت بحاجة إلى دفع قيم مختلفة متعددة، فيجب عليك إما استخدام "(X)PUSHs"
وحدات الماكرو، أو استخدم وحدات الماكرو "m(X)PUSH[iunp]" الجديدة، والتي لا يستخدم أي منها "TARG".
تقوم وحدات الماكرو "(X)PUSHs" ببساطة بدفع SV* على المكدس، والذي، كما هو مذكور ضمن "XSUBs و
the Argument Stack"، غالبًا ما تحتاج إلى أن تكون "مميتة". تعمل وحدات الماكرو "m(X)PUSH[iunp]" الجديدة على إنشاء
من الأسهل تحقيق ذلك عن طريق إنشاء بشر جديد لك (عبر "(X)PUSHmortal")،
دفع ذلك إلى المكدس (تمديده إذا لزم الأمر في حالة "mXPUSH[iunp]"
وحدات الماكرو)، ثم تحديد قيمتها. وبالتالي، بدلاً من كتابة هذا "لإصلاح" المثال
في الاعلى:

XPUSHs(sv_2mortal(newSViv(10)))
XPUSHs(sv_2mortal(newSViv(20)))

يمكنك ببساطة أن تكتب:

mXPUSHi(10)
mXPUSHi(20)

في ملاحظة ذات صلة، إذا كنت تستخدم "(X)PUSH[iunp]"، فستحتاج إلى "dTARG" في
تعريفات المتغيرات الخاصة بك حتى تتمكن وحدات الماكرو "*PUSH*" من الاستفادة من المتغير المحلي
"الهدف". انظر أيضًا "dTARGET" و"dXSTARG".

دفاتر الملاحظات
ويبقى السؤال مطروحًا متى تكون SVs الهدفيتم إنشاء رموز التشغيل. ال
الإجابة هي أنه يتم إنشاؤها عندما تكون الوحدة الحالية - روتينًا فرعيًا أو ملفًا (لأكواد التشغيل).
للبيانات خارج الإجراءات الفرعية)--يتم تجميعها. خلال هذا الوقت مجهول خاص
يتم إنشاء مصفوفة Perl، والتي تسمى لوحة المسودة للوحدة الحالية.

تحتفظ لوحة المسودة بالمفردات SV التي تعتبر معجمية للوحدة الحالية وهي أهداف
رموز التشغيل. ذكرت نسخة سابقة من هذه الوثيقة أنه يمكن للمرء أن يستنتج أن SV يعيش
على لوحة المسودة من خلال النظر إلى أعلامها: تحتوي المفردات على مجموعة "SVs_PADMY"، و الهدفق
مجموعة "SVs_PADTMP". ولكن هذا لم يكن صحيحا تماما. يمكن تعيين "SVs_PADMY" على ملف
المتغير الذي لم يعد موجودًا في أي لوحة. بينما الهدفلقد تم تعيين "SVs_PADTMP".
يمكن أيضًا تعيينها على متغيرات لم تكن موجودة مطلقًا في اللوحة، ولكنها مع ذلك تتصرف على هذا النحو
الهدفس. اعتبارًا من الإصدار 5.21.5 من Perl، لم تعد علامة "SVs_PADMY" مستخدمة وتم تعريفها على أنها 0.
يُرجع "SvPADMY()" الآن القيمة الحقيقية لأي شيء بدون "SVs_PADTMP".

المراسلات بين OPs و الهدفs ليس 1 إلى 1. العمليات التشغيلية المختلفة في الترجمة
يمكن لشجرة الوحدة استخدام نفس الهدف، إذا كان ذلك لا يتعارض مع المتوقع
حياة مؤقتة.

دفاتر الملاحظات و العودية
في الواقع، ليس صحيحًا بنسبة 100% أن الوحدة المترجمة تحتوي على مؤشر إلى لوحة المسودة AV.
في الواقع يحتوي على مؤشر AV لعنصر واحد (في البداية)، وهذا العنصر هو
لوحة المسودة AV. لماذا نحتاج إلى مستوى إضافي من المراوغة؟

الجواب هو العودية، و ربما المواضيع. كلاهما يمكن أن يخلق عدة عمليات تنفيذ
مؤشرات الخوض في نفس الروتين الفرعي. بالنسبة للطفل الروتيني لا يكتب فوق
مؤقتات للوالد الروتيني الفرعي (يغطي عمره المكالمة إلى الطفل)،
يجب أن يكون لدى الوالدين والطفل وسادات خدش مختلفة. (و ينبغي أن تكون المعجمية
منفصلة على أي حال!)

لذلك يتم إنشاء كل روتين فرعي مع مجموعة من لوحات المسودة (بطول 1). على كل دخول إلى
يتم التحقق من الروتين الفرعي من أن العمق الحالي للتكرار ليس أكثر من
طول هذه المصفوفة، وإذا كان الأمر كذلك، فسيتم إنشاء لوحة مسودة جديدة ودفعها إلى المصفوفة.

إنّ كافة أنواع عهود الـ الهدفالعناصر الموجودة على لوحة المسودة هذه هي عناصر "غير محددة"، ولكن تم وضع علامة عليها بالفعل بأنها صحيحة
الأعلام.

ذاكرة توزيع


توزيع
يجب معالجة كل الذاكرة المخصصة للاستخدام مع وظائف Perl API باستخدام ملف
وحدات الماكرو الموضحة في هذا القسم. توفر وحدات الماكرو الشفافية اللازمة بين
الاختلافات في تطبيق malloc الفعلي المستخدم داخل Perl.

يُقترح أن تقوم بتمكين إصدار malloc الذي يتم توزيعه مع Perl. هو - هي
يحتفظ بمجموعات بأحجام مختلفة من الذاكرة غير المخصصة لتلبية طلبات التخصيص
بسرعة أكبر. ومع ذلك، في بعض الأنظمة الأساسية، قد يتسبب ذلك في حدوث أخطاء زائفة أو أخطاء مجانية.

يتم استخدام وحدات الماكرو الثلاثة التالية لتخصيص الذاكرة في البداية:

Newx(مؤشر، رقم، نوع)؛
Newxc(pointer, number, type, cast);
Newxz(مؤشر، رقم، نوع)؛

يجب أن تكون الوسيطة الأولى "المؤشر" هي اسم المتغير الذي سيشير إلى الملف الجديد
الذاكرة المخصصة.

تحدد الوسيطتان الثانية والثالثة "الرقم" و"النوع" عدد النوع المحدد
ينبغي تخصيص بنية البيانات. يتم تمرير الوسيطة "type" إلى "sizeof". ال
يجب استخدام الوسيطة النهائية لـ "Newxc"، "cast"، إذا كانت وسيطة "المؤشر" مختلفة
من وسيطة "النوع".

بخلاف وحدات الماكرو "Newx" و"Newxc"، يستدعي الماكرو "Newxz" "memzero" لصفر الكل
الذاكرة المخصصة حديثا.

إعادة تخصيص
تجديد (المؤشر، الرقم، النوع)؛
Renewc(pointer, number, type, cast);
Safefree (المؤشر)

تُستخدم وحدات الماكرو الثلاثة هذه لتغيير حجم المخزن المؤقت للذاكرة أو لتحرير جزء من الذاكرة
تعد هناك حاجة. تتطابق وسيطتا "Renew" و"Renewc" مع وسيطتي "New" و"Newc".
استثناء عدم الحاجة إلى وسيطة "ملف تعريف الارتباط السحري".

متحرك
نقل (المصدر، الوجهة، الرقم، النوع)؛
نسخ (المصدر، الوجهة، الرقم، النوع)؛
صفر (الوجهة، الرقم، النوع)؛

يتم استخدام وحدات الماكرو الثلاثة هذه لنقل الذاكرة المخصصة مسبقًا أو نسخها أو تصفيتها. ال
تشير وسيطتا "المصدر" و"الوجهة" إلى نقطتي بداية المصدر والوجهة. بيرل
سيتم نقل أو نسخ أو صفر مثيلات "رقم" بحجم بنية بيانات "النوع".
(باستخدام وظيفة "sizeof").

بيرليو


أحدث الإصدارات التطويرية لـ Perl كانت تجرب إزالة إصدارات Perl
الاعتماد على مجموعة الإدخال / الإخراج القياسية "العادية" والسماح لتطبيقات stdio الأخرى بذلك
يستخدم. يتضمن ذلك إنشاء طبقة تجريد جديدة تقوم بعد ذلك باستدعاء أي منها
تم تجميع تنفيذ stdio Perl مع. يجب على جميع XSUBs الآن استخدام الوظائف الموجودة في
طبقة تجريد PerlIO ولا تضع أي افتراضات حول نوع stdio
تم استخدامها.

للحصول على وصف كامل لتجريد PerlIO، راجع perlapio.

جمعت الكود


رمز شجرة
نحن هنا نصف النموذج الداخلي الذي يتم تحويل الكود الخاص بك إليه بواسطة Perl. ابدأ بأمر بسيط
مثال:

$a = $b + $c;

يتم تحويل هذا إلى شجرة مشابهة لهذه:

يسند إلى
/ \
+ $أ
/ \
$ ب $ ج

(لكنها أكثر تعقيدًا بعض الشيء). تعكس هذه الشجرة الطريقة التي قام بها Perl بتحليل التعليمات البرمجية الخاصة بك، ولكن
لا علاقة له بأمر التنفيذ. هناك "خيط" إضافي يمر
عقد الشجرة التي توضح ترتيب تنفيذ العقد. في مبسطتنا
المثال أعلاه يبدو كما يلي:

$b ---> $c ---> + ---> $a ---> إسناد إلى

ولكن مع شجرة الترجمة الفعلية لـ "$a = $b + $c" فالأمر مختلف: بعض العقد الأمثل
بعيدا. كنتيجة طبيعية، على الرغم من أن الشجرة الفعلية تحتوي على عقد أكثر من تلك المبسطة
على سبيل المثال، أمر التنفيذ هو نفسه كما في مثالنا.

دراسة القادم شجرة
إذا كان لديك لغة Perl الخاصة بك مجمعة لتصحيح الأخطاء (يتم ذلك عادةً باستخدام "-DDEBUGGING" على
"تكوين" سطر الأوامر)، يمكنك فحص الشجرة المترجمة عن طريق تحديد "-Dx" على الملف
سطر أوامر بيرل. يستغرق الإخراج عدة أسطر لكل عقدة، ويبدو الأمر كذلك بالنسبة إلى "$b+$c".
هذه:

5 النوع = إضافة ===> 6
الهدف = 1
الأعلام = (العددية، الأطفال)
{
النوع = خالية ===> (4)
(كان rv2sv)
الأعلام = (العددية، الأطفال)
{
3 النوع = gvsv ===> 4
الأعلام = (العددية)
GV = رئيسي :: ب
}
}
{
النوع = خالية ===> (5)
(كان rv2sv)
الأعلام = (العددية، الأطفال)
{
4 النوع = gvsv ===> 5
الأعلام = (العددية)
GV = الرئيسي::c
}
}

تحتوي هذه الشجرة على 5 عقد (واحدة لكل محدد "TYPE")، ولم يتم تحسين 3 منها فقط
(واحد لكل رقم في العمود الأيسر). يتوافق الأطفال المباشرون للعقدة المحددة
إلى أزواج "{}" على نفس مستوى المسافة البادئة، وبالتالي فإن هذه القائمة تتوافق مع الشجرة:

تضيف
/ \
لا شيء
| |
gvsv gvsv

تتم الإشارة إلى أمر التنفيذ بعلامات "===>"، وبالتالي فهو "3 4 5 6" (العقدة 6 ليست كذلك
مدرج في القائمة أعلاه)، أي "gvsv gvsv أضف أيًا كان".

تمثل كل عقدة من هذه العقد عملية أساسية داخل نواة لغة Perl. ال
يمكن العثور على الكود الذي ينفذ كل عملية في ملف ص*.ج الملفات؛ الوظيفة التي
ينفذ المرجع بالنوع "gvsv" وهو "pp_gvsv"، وهكذا. كما تظهر الشجرة أعلاه،
العمليات المختلفة لها أعداد مختلفة من الأطفال: "add" هو عامل تشغيل ثنائي، كما هو الحال مع المرء
نتوقع، وكذلك لديه طفلان. لاستيعاب الأعداد المختلفة المختلفة
الأطفال، هناك أنواع مختلفة من بنية بيانات العمليات، وهي ترتبط ببعضها البعض
طرق مختلفة.

أبسط نوع من بنية العمليات هو "OP": لا يحتوي على أطفال. مشغلي الأحادي,
"UNOP"، لديها طفل واحد، ويُشار إلى ذلك بواسطة الحقل "op_first". عوامل التشغيل الثنائية
لا تحتوي ("BINOP") على حقل "op_first" فحسب، بل تحتوي أيضًا على حقل "op_last". أكثر
النوع المعقد من العمليات هو "LISTOP"، الذي يحتوي على أي عدد من الأطفال. في هذه الحالة،
تتم الإشارة إلى الطفل الأول بواسطة "op_first" وإلى الطفل الأخير بواسطة "op_last". الاطفال في
يمكن العثور على Between باتباع مؤشر "OpSIBLING" بشكل متكرر من الطفل الأول
إلى الأخير (ولكن انظر أدناه).

هناك أيضًا بعض أنواع العمليات الأخرى: يحتوي "PMOP" على تعبير عادي، ولا يحتوي على أي تعبير عادي
أطفال، و"LOOP" قد يكون لها أطفال أو لا يكون لها أطفال. إذا كان الحقل "op_children" غير
صفر، فهو يتصرف مثل "LISTOP". لتعقيد الأمور، إذا كان "UNOP" هو في الواقع "فارغ"
op بعد التحسين (راجع "ترجمة التمريرة 2: نشر السياق") سيظل موجودًا
الأطفال وفقا لنوعه السابق.

وأخيرا، هناك "LOGOP"، أو عملية منطقية. مثل "LISTOP"، يحتوي هذا على طفل واحد أو أكثر،
لكنه لا يحتوي على حقل "op_last": لذلك عليك اتباع "op_first" ثم
سلسلة "OpSIBLING" نفسها للعثور على الطفل الأخير. بدلاً من ذلك، يحتوي على حقل "op_other"، والذي
يشبه الحقل "op_next" الموضح أدناه، ويمثل حقلاً بديلاً
مسار التنفيذ. عوامل التشغيل مثل "و" و"أو" و"؟" هي "LOGOP". لاحظ أنه بشكل عام،
قد لا يشير "op_other" إلى أي من العناصر الفرعية المباشرة لـ "LOGOP".

بدءًا من الإصدار 5.21.2، تم إنشاء Perls بالتعريف التجريبي "-DPERL_OP_PARENT"
أضف علامة منطقية إضافية لكل عملية، "op_moresib". عندما لا يتم ضبطه، فهذا يشير إلى ذلك
هذه هي العملية الأخيرة في سلسلة "OpSIBLING". يؤدي هذا إلى تحرير الحقل "op_sibling" الموجود على الملف
آخر شقيق للإشارة إلى المرجع الأصلي. ضمن هذا الإصدار، يتم أيضًا إعادة تسمية هذا الحقل
"op_sibparent" لتعكس دورها المشترك. الماكرو OpSIBLING(o) يلتف حول هذا الخاص
السلوك، وترجع دائمًا NULL على الأخ الأخير. مع هذا بناء op_parent(o)
يمكن استخدام الوظيفة للعثور على أصل أي عملية. وبالتالي من أجل التوافق إلى الأمام، أنت
يجب دائمًا استخدام الماكرو OpSIBLING(o) بدلاً من الوصول إلى "op_sibling" مباشرةً.

هناك طريقة أخرى لفحص الشجرة وهي استخدام وحدة الواجهة الخلفية للمترجم، مثل B::Concise.

جمع pass 1: التحقق الروتين
يتم إنشاء الشجرة بواسطة المترجم while ياك كود يغذي الانشاءات عليه
يتعرف. منذ ياك يعمل من الأسفل إلى الأعلى، وكذلك الحال مع التمريرة الأولى لتجميع بيرل.

ما يجعل هذا المرور مثيرًا للاهتمام لمطوري Perl هو أنه قد يكون هناك بعض التحسين
يتم تنفيذها على هذا المرور. هذا هو التحسين من خلال ما يسمى "إجراءات التحقق". ال
تم وصف المراسلات بين أسماء العقد وإجراءات التحقق المقابلة في
opcode.pl (لا تنس تشغيل "make regen_headers" إذا قمت بتعديل هذا الملف).

يتم استدعاء روتين التحقق عندما يتم إنشاء العقدة بالكامل باستثناء التنفيذ-
موضوع الطلب. نظرًا لأنه في هذا الوقت لا توجد روابط خلفية لما تم إنشاؤه حاليًا
العقدة، يمكن للمرء إجراء أي عملية على العقدة ذات المستوى الأعلى، بما في ذلك تحريرها و/أو
إنشاء عقد جديدة فوقها/تحتها.

يقوم روتين التحقق بإرجاع العقدة التي يجب إدراجها في الشجرة (إذا كان الجزء العلوي
لم يتم تعديل عقدة المستوى، يقوم روتين التحقق بإرجاع الوسيطة الخاصة به).

وفقًا للاتفاقية، إجراءات التحقق لها أسماء "ck_*". يتم استدعاؤهم عادةً من "new*OP"
الإجراءات الفرعية (أو "التحويل") (والتي بدورها يتم استدعاؤها من perly.y).

جمع pass 1a: ثابت قابلة للطي
مباشرة بعد استدعاء روتين التحقق، يتم التحقق من وجود العقدة التي تم إرجاعها
وقت الترجمة قابل للتنفيذ. إذا كانت (تم الحكم على القيمة بأنها ثابتة) فهي على الفور
تم إعدامه، و أ ثابت العقدة ذات "قيمة الإرجاع" للشجرة الفرعية المقابلة هي
استبدال بدلا من ذلك. يتم حذف الشجرة الفرعية.

إذا لم يتم تنفيذ الطي المستمر، فسيتم إنشاء خيط أمر التنفيذ.

جمع pass 2: سياق الكلام نشر
عندما يُعرف سياق جزء من شجرة الترجمة، يتم نشره للأسفل من خلال
شجرة. في هذا الوقت يمكن أن يحتوي السياق على 5 قيم (بدلاً من 2 لسياق وقت التشغيل):
باطلة، منطقية، عددية، قائمة، وlvalue. على النقيض من التمريرة 1 فإن هذه التمريرة هي
تتم معالجتها من أعلى إلى أسفل: يحدد سياق العقدة سياق أطفالها.

يتم إجراء تحسينات إضافية تعتمد على السياق في هذا الوقت. منذ عند هذا
في اللحظة التي تحتوي فيها شجرة الترجمة على مراجع خلفية (عبر مؤشرات "السلسلة")، لا يمكن أن تكون العقد كذلك
مجانا()د الآن. للسماح بالعقد البعيدة المُحسّنة في هذه المرحلة، يتم استخدام هذه العقد باطل()تم تحديده
بدلا من مجانا()ing (أي تم تغيير نوعها إلى OP_NULL).

جمع pass 3: ثقب الباب التحسين
بعد إنشاء شجرة الترجمة لروتين فرعي (أو لـ "تقييم" أو ملف)، يتم إنشاء ملف
يتم تنفيذ تمرير إضافي على التعليمات البرمجية. هذا التمرير ليس من أعلى إلى أسفل أو من أسفل إلى أعلى،
ولكن في أمر التنفيذ (مع تعقيدات إضافية للشروط الشرطية).
تخضع التحسينات التي يتم إجراؤها في هذه المرحلة لنفس القيود الموجودة في التمرير
2.

يتم إجراء تحسينات ثقب الباب عن طريق استدعاء الوظيفة التي يشير إليها المتغير العام
"PL_peepp". افتراضيًا، يستدعي "PL_peepp" فقط الوظيفة التي يشير إليها العامل العمومي
المتغير "PL_rpeepp". افتراضيًا، يؤدي ذلك إلى إجراء بعض الإصلاحات والتحسينات الأساسية للعمليات
على طول سلسلة عمليات أمر التنفيذ، ويستدعي بشكل متكرر "PL_rpeepp" لكل سلسلة جانبية
من العمليات (الناتجة عن الشروط الشرطية). قد توفر الإضافات تحسينات إضافية أو
الإصلاحات، والربط إما بالمرحلة الفرعية أو المرحلة العودية، مثل هذا:

ثابت peep_t prev_peepp؛
الفراغ الثابت my_peep(pTHX_ OP *o)
{
/* يتم وضع التحسين المخصص لكل روتين فرعي هنا */
prev_peepp(aTHX_ o);
/* يمكن أيضًا وضع التحسين المخصص لكل روتين فرعي هنا */
}
حذاء طويل:
prev_peepp = PL_peepp;
PL_peepp = my_peep;

ثابت peep_t prev_rpeepp؛
الفراغ الثابت my_rpeep(pTHX_ OP *o)
{
OP *orig_o = o;
for(; o; o = o->op_next) {
/* يظهر التحسين المخصص لكل عملية هنا */
}
prev_rpeepp(aTHX_ orig_o);
}
حذاء طويل:
prev_rpeepp = PL_rpeepp;
PL_rpeepp = my_rpeep;

قابلية runops
يتم تنفيذ شجرة الترجمة في وظيفة runops. هناك نوعان من وظائف runops، في
تشغيل.ج وفي تفريغ ج. يتم استخدام "Perl_runops_debug" مع DEBUGGING و
يتم استخدام "Perl_runops_standard" بطريقة أخرى. للتحكم الدقيق في تنفيذ
شجرة الترجمة من الممكن توفير وظيفة runops الخاصة بك.

ربما يكون من الأفضل نسخ إحدى وظائف التشغيل الحالية وتغييرها لتناسب احتياجاتك
الاحتياجات. ثم، في قسم BOOT في ملف XS، أضف السطر:

PL_runops = my_runops;

يجب أن تكون هذه الوظيفة فعالة قدر الإمكان للحفاظ على تشغيل برامجك بأسرع ما يمكن
ممكن.

وقت الترجمة نطاق السنانير
اعتبارًا من الإصدار 5.14 من Perl، من الممكن الارتباط بآلية النطاق المعجمي في وقت الترجمة باستخدام
"بيرل_بلوك_هوك_تسجيل". يتم استخدام هذا مثل هذا:

STATIC void my_start_hook(pTHX_int full);
STATIC BHK my_hooks؛

حذاء طويل:
BhkENTRY_set(&my_hooks, bhk_start, my_start_hook);
Perl_blockhook_register(aTHX_ &my_hooks);

سيؤدي هذا إلى استدعاء "my_start_hook" في بداية تجميع كل معجم
نِطَاق. السنانير المتاحة هي:

"باطل bhk_start(pTHX_int كامل)"
يتم استدعاء هذا مباشرة بعد بدء نطاق معجمي جديد. لاحظ أن رمز بيرل مثل

إذا (س) {...}

ينشئ نطاقين: الأول يبدأ عند "(" ويحتوي على "full == 1"، ويبدأ الثاني
في "{" ويحتوي على "كامل == 0". كلاهما ينتهي عند "}"، لذلك يدعو إلى "البدء" و
سوف يتطابق "pre/post_end". أي شيء يتم دفعه إلى مكدس الحفظ بواسطة هذا الخطاف سيكون
ظهرت قبل انتهاء النطاق مباشرة (بين الخطافين "pre_" و"post_end"، في الواقع).

"باطل bhk_pre_end(pTHX_ OP **o)"
يتم استدعاء هذا في نهاية النطاق المعجمي، مباشرة قبل تفكيك المكدس. o is
جذر opttree الذي يمثل النطاق؛ إنه مؤشر مزدوج حتى تتمكن من ذلك
استبدل OP إذا كنت بحاجة إلى ذلك.

"باطل bhk_post_end(pTHX_ OP **o)"
يتم استدعاء هذا في نهاية النطاق المعجمي، مباشرة بعد تفكيك المكدس. o كما هو
فوق. لاحظ أنه من الممكن تداخل الاستدعاءات إلى "pre_" و"post_end"، إذا كان هناك
هو شيء موجود في مكدس الحفظ يستدعي تقييم السلسلة.

"باطل bhk_eval(pTHX_ OP *const o)"
يتم استدعاء هذا قبل البدء في تجميع "سلسلة تقييم" و"تنفيذ ملف" و"يتطلب"
أو "الاستخدام"، بعد إعداد التقييم. o هو OP الذي طلب التقييم، و
سيكون عادةً "OP_ENTEREVAL" أو "OP_DOFILE" أو "OP_REQUIRE".

بمجرد حصولك على وظائف الخطاف الخاصة بك، فإنك تحتاج إلى بنية "BHK" لوضعها فيها. هذا هو الأفضل
لتخصيصه بشكل ثابت، حيث لا توجد طريقة لتحريره بمجرد تسجيله. ال
يجب إدراج مؤشرات الدالة في هذه البنية باستخدام الماكرو "BhkENTRY_set"،
والتي ستقوم أيضًا بتعيين علامات تشير إلى الإدخالات الصالحة. إذا كنت بحاجة إلى تخصيص
"BHK" الخاص بك ديناميكيًا لسبب ما، تأكد من تصفيره قبل البدء.

بمجرد التسجيل، لا توجد آلية لإيقاف تشغيل هذه الخطافات، لذلك إذا كان ذلك ضروريًا
سوف تحتاج إلى القيام بذلك بنفسك. من المحتمل أن يكون الإدخال في "%^H" هو أفضل طريقة، لذا فإن
يتم تحديد التأثير بشكل معجمي؛ ومع ذلك فمن الممكن أيضًا استخدام "BhkDISABLE" و
وحدات الماكرو "BhkENABLE" لتبديل الإدخالات وإيقاف تشغيلها مؤقتًا. يجب أن تكون على علم أيضًا
بشكل عام، سيتم فتح نطاق واحد على الأقل قبل فتح الامتداد الخاص بك
تم تحميلها، لذلك سترى بعض أزواج "ما قبل/ما بعد النهاية" التي لم يكن لها "بداية" مطابقة.

دراسة داخلي البيانات الهياكل مع القادم "أحمق" وظائف


للمساعدة في تصحيح الأخطاء، الملف المصدر تفريغ ج يحتوي على عدد من الوظائف التي تنتج
الإخراج المنسق لهياكل البيانات الداخلية.

أكثر هذه الوظائف استخدامًا هي "Perl_sv_dump"؛ يتم استخدامه لإلقاء SVs،
AVs، HVs، والسير الذاتية. تستدعي الوحدة النمطية "Devel::Peek" "sv_dump" لإنتاج مخرجات تصحيح الأخطاء
من Perl-space، لذلك يجب أن يكون مستخدمو هذه الوحدة على دراية بتنسيقها بالفعل.

يمكن استخدام "Perl_op_dump" لتفريغ بنية "OP" أو أي من مشتقاتها، و
ينتج مخرجات مشابهة لـ "Perl -Dx"؛ في الواقع، "Perl_dump_eval" سوف يتخلص من الجذر الرئيسي
للكود الذي يتم تقييمه، تمامًا مثل "-Dx".

الوظائف المفيدة الأخرى هي "Perl_dump_sub"، والتي تحول "GV" إلى شجرة العمليات،
"Perl_dump_packsubs" الذي يستدعي "Perl_dump_sub" على كافة الإجراءات الفرعية في حزمة مثل
لذا: (لحسن الحظ، هذه جميعها xsubs، لذا لا توجد شجرة op)

(gdb) طباعة Perl_dump_packsubs(PL_defstash)

سمات SUB::bootstrap = (xsub 0x811fedc 0)

SUB UNIVERSAL::can = (xsub 0x811f50c 0)

الفرعي العالمي::isa = (xsub 0x811f304 0)

SUB UNIVERSAL::VERSION = (xsub 0x811f7ac 0)

SUB DynaLoader::boot_DynaLoader = (xsub 0x805b188 0)

و"Perl_dump_all"، الذي يتخلص من كافة الإجراءات الفرعية الموجودة في المخبأ وشجرة العمليات الخاصة بـ
الجذر الرئيسي.

كيفية متعدد مترجمين و التزامن . أيد


خلفيّة و بيرل_IMPLICIT_CONTEXT
يمكن اعتبار مترجم Perl بمثابة صندوق مغلق: فهو يحتوي على واجهة برمجة التطبيقات (API) لتغذيته بالكود أو
وإلا فإنه يجعلها تفعل أشياء، ولكن لديها أيضًا وظائف لاستخدامها الخاص. هذه الرائحة أ
يشبه إلى حد كبير كائنًا، وهناك طرق يمكنك من خلالها إنشاء لغة Perl بحيث يمكنك الحصول على عدة كائنات
مترجمون فوريون، مع مترجم واحد يتم تمثيله إما على شكل بنية C، أو داخل ملف
هيكل خاص بالخيط. تحتوي هذه الهياكل على كل السياق وحالة ذلك
مترجم.

يتحكم ماكرو واحد في نكهة بناء Perl الرئيسية: التعددية. بناء MULTIPLICITY لديه
بنية C التي تحزم كل حالة المترجم. مع بيرلز تمكين التعددية،
يتم أيضًا تعريف PERL_IMPLICIT_CONTEXT بشكل طبيعي، ويتيح الدعم لتمرير ملف
الوسيطة الأولى "المخفية" التي تمثل بنيات البيانات الثلاثة. التعدد يجعل
يمكن استخدام Perls متعددة الخيوط (مع نموذج خيوط ithreads المرتبط بالماكرو
USE_ITHREADS.)

وحدتي ماكرو "تغليف" أخريين هما PERL_GLOBAL_STRUCT وPERL_GLOBAL_STRUCT_PRIVATE
(الأخير ينقلب على الأول، والأول ينقلب على التعدد).
يؤدي PERL_GLOBAL_STRUCT إلى تغليف كافة المتغيرات الداخلية لـ Perl داخل متغير واحد
البنية العامة، struct perl_vars، يمكن الوصول إليها كـ (globals) &PL_Vars أو PL_VarsPtr أو
وظيفة بيرل_جيتفارس (). يذهب PERL_GLOBAL_STRUCT_PRIVATE خطوة أخرى إلى الأمام، فهو موجود
لا يزال بنية واحدة (المخصصة في الأساسية() إما من الكومة أو من المكدس) ولكن هناك
ولا توجد رموز بيانات عالمية تشير إليها. وفي كلتا الحالتين ينبغي أن يكون الهيكل العالمي
تمت تهيئته كأول شيء في الأساسية() استخدام بيرل_ينيت_جلوبال_ستروك() و
هدم في المقابل بعد ذلك بيرل_فري() استخدام بيرل_free_global_struct()الرجاء مراجعة
miniperlmain.c للحصول على تفاصيل الاستخدام. قد تحتاج أيضًا إلى استخدام "dVAR" في الترميز الخاص بك
"قم بتعريف المتغيرات العامة" عند استخدامها. تقوم dTHX بهذا نيابةً عنك
تلقائيا.

لمعرفة ما إذا كانت لديك بيانات غير ثابتة، يمكنك استخدام "nm" متوافق مع BSD (أو GNU):

نانومتر libperl.a | grep -v '[TURtr]'

إذا كان هذا يعرض أي رموز "D" أو "d" (أو ربما "C" أو "c")، فإن لديك بيانات غير ثابتة.
الرموز التي تمت إزالتها "grep" هي كما يلي: "Tt" هي نص، أو الكود، "Rr" هي اقرأ-
فقط (const)، والحرف "U" هو ، ويشار إلى الرموز الخارجية.

الاختبار t/porting/libperl.t هل يقوم هذا النوع من التحقق من سلامة الرمز على "libperl.a".

لأسباب التوافق مع الإصدارات السابقة، لا يتم إخفاء تعريف PERL_GLOBAL_STRUCT فقط
جميع الرموز الموجودة داخل بنية عامة كبيرة: يتم ترك بعض جداول PerlIO_xxx vtables مرئية. ال
يقوم PERL_GLOBAL_STRUCT_PRIVATE بإخفاء كل شيء (انظر كيفية استخدام PERLIO_FUNCS_DECL).

من الواضح أن كل هذا يتطلب طريقة لكي تكون وظائف Perl الداخلية إما روتينات فرعية
مع أخذ نوع ما من البنية كوسيطة أولى، أو لا تأخذ الإجراءات الفرعية أي شيء كوسيطة
الحجة الأولى. لتمكين هاتين الطريقتين المختلفتين جدًا لبناء المترجم الفوري، فإن
يستخدم مصدر Perl (كما هو الحال في العديد من المواقف الأخرى) الاستخدام المكثف لوحدات الماكرو و
اصطلاحات تسمية الروتين الفرعي.

المشكلة الأولى: تحديد الوظائف التي ستكون وظائف API عامة وأيها ستكون
خاص. جميع الوظائف التي تبدأ أسماؤها بـ "S_" هي وظائف خاصة (فكر في "S" لـ "secret" أو
"ثابتة"). تبدأ جميع الوظائف الأخرى بـ "Perl_"، ولكن فقط لأن الوظيفة تبدأ
مع "Perl_" لا يعني أنه جزء من واجهة برمجة التطبيقات (API). (راجع "الوظائف الداخلية".)
أسهل طريقة لتكون بالتأكيد الوظيفة التي تعد جزءًا من واجهة برمجة التطبيقات (API) هي العثور على إدخالها في perlapi. لو
إنه موجود في perlapi، وهو جزء من واجهة برمجة التطبيقات (API). إذا لم يحدث ذلك، وتعتقد أنه ينبغي أن يكون
(على سبيل المثال، أنت في حاجة إليها لامتدادك)، أرسل بريدًا عبر perlbug موضحًا سبب اعتقادك بذلك
يجب ان يكون.

المشكلة الثانية: يجب أن يكون هناك بناء الجملة بحيث نفس الإعلانات والمكالمات الروتينية
يمكنهم تمرير البنية كوسيطة أولى، أو عدم تمرير أي شيء. لحل هذه المشكلة،
تتم تسمية الإجراءات الفرعية وإعلانها بطريقة معينة. هذه بداية نموذجية لـ أ
الوظيفة الثابتة المستخدمة داخل شجاعة Perl:

الفراغ ثابت
S_incline(pTHX_ شار *s)

STATIC تصبح "ثابتة" في لغة C، وقد يتم تحديدها #define'd إلى لا شيء في بعض التكوينات في
المستقبل.

وظيفة عامة (أي جزء من واجهة برمجة التطبيقات الداخلية، ولكن ليس بالضرورة أن يتم الموافقة على استخدامها
في الامتدادات) يبدأ هكذا:

باطل
Perl_sv_setiv(pTHX_ SV* dsv, IV num)

"pTHX_" هو واحد من عدد من وحدات الماكرو (في بيرل) التي تخفي تفاصيل
سياق المترجم. يرمز THX إلى "thread" أو "this" أو "thingy" حسب الحالة.
(ولا، جورج لوكاس ليس متورطًا. :-) يمكن أن تكون الشخصية الأولى "p" لـ a
pالنموذج الأولي، "أ" ل aحجة، أو "د" ل dتوضيح، لذلك لدينا "pTHX"، و"aTHX" و"dTHX"،
ومتغيراتها.

عندما يتم إنشاء لغة Perl بدون الخيارات التي تحدد PERL_IMPLICIT_CONTEXT، فلا يوجد خيار أول
الوسيطة التي تحتوي على سياق المترجم. الشرطة السفلية الزائدة في الماكرو pTHX_
يشير إلى أن توسيع الماكرو يحتاج إلى فاصلة بعد وسيطة السياق لأن أخرى
الحجج تتبعه. إذا لم يتم تعريف PERL_IMPLICIT_CONTEXT، فسيتم تجاهل pTHX_، و
لم يتم تصميم الروتين الفرعي ليأخذ الوسيطة الإضافية. شكل الماكرو
يتم استخدام بدون الشرطة السفلية الزائدة عندما لا تكون هناك وسائط صريحة إضافية.

عندما تستدعي دالة أساسية أخرى، يجب عليها تمرير السياق. عادة ما يتم إخفاء هذا عبر
وحدات الماكرو. خذ بعين الاعتبار "sv_setiv". ويتوسع إلى شيء من هذا القبيل:

#ifdef PERL_IMPLICIT_CONTEXT
#define sv_setiv(a,b) Perl_sv_setiv(aTHX_ a, b)
/* لا يمكن القيام بذلك مع دوال vararg، انظر أدناه */
#else
#define sv_setiv Perl_sv_setiv
#endif

يعمل هذا بشكل جيد، ويعني أن مؤلفي XS يمكنهم الكتابة بكل سرور:

sv_setiv(foo, bar);

ولا يزال يعمل ضمن جميع الأوضاع التي كان من الممكن تجميع لغة Perl بها.

هذا لا يعمل بشكل واضح مع وظائف varargs، على الرغم من أن وحدات الماكرو تشير ضمنا إلى أن
عدد الحجج معروف مسبقًا. وبدلاً من ذلك، نحتاج إما إلى توضيحها بالكامل،
تمرير "aTHX_" كوسيطة أولى (يميل جوهر Perl إلى القيام بذلك باستخدام وظائف مثل
Perl_warner)، أو استخدم إصدارًا خاليًا من السياق.

يُطلق على الإصدار الخالي من السياق من Perl_warner اسم Perl_warner_nocontext، ولا يستغرق وقتًا
الحجة الزائدة. بدلا من ذلك يفعل dTHX؛ للحصول على السياق من التخزين المحلي لمؤشر الترابط.
نحن "#define warner Perl_warner_nocontext" حتى تحصل الامتدادات على توافق المصدر عند
تكلفة الأداء. (تمرير وسيطة أرخص من انتزاعها من مؤشر ترابط محلي
تخزين.)

يمكنك تجاهل [pad] THXx عند تصفح رؤوس/مصادر Perl. تلك مخصصة بدقة ل
استخدامها داخل النواة. يجب أن تكون الإضافات وأجهزة التضمين على دراية بـ [pad] THX فقط.

So ماذا حدث إلى dTHR؟
تم تقديم "dTHR" في الإصدار 5.005 من Perl لدعم نموذج الخيط الأقدم. الخيط الأقدم
يستخدم النموذج الآن آلية "THX" لتمرير مؤشرات السياق، لذا فإن "dTHR" ليس كذلك
مفيدة بعد الآن. لا يزال الإصدار 5.6.0 من Perl والإصدارات الأحدث مزودًا به للتوافق مع الإصدارات السابقة من المصدر،
ولكن تم تعريفه على أنه محظور.

كيفية do I تستخدم الكل in ملحقات؟
عندما يتم إنشاء لغة Perl باستخدام PERL_IMPLICIT_CONTEXT، فإن الامتدادات التي تستدعي أي وظائف في
سوف تحتاج Perl API إلى تمرير وسيطة السياق الأولية بطريقة ما. الركلة هي أنك
سيحتاج إلى كتابته بطريقة تجعل الامتداد يتم تجميعه عندما لا يقوم Perl بذلك
تم إنشاؤه مع تمكين PERL_IMPLICIT_CONTEXT.

هناك ثلاث طرق للقيام بذلك. أولاً، الطريقة السهلة ولكن غير الفعالة، وهي أيضًا الطريقة
افتراضيًا، من أجل الحفاظ على توافق المصدر مع الامتدادات: كلما XSUB.h is
#included، فهو يعيد تعريف وحدات الماكرو aTHX وaTHX_ لاستدعاء وظيفة تقوم بإرجاع
سياق. وهكذا شيء من هذا القبيل:

sv_setiv(sv, num);

في ملحقك سيتم ترجمته إلى هذا عندما يكون PERL_IMPLICIT_CONTEXT ساري المفعول:

Perl_sv_setiv(Perl_get_context(), sv, num);

أو إلى هذا غير ذلك:

Perl_sv_setiv(sv, num);

ليس عليك القيام بأي شيء جديد في ملحقك للحصول على هذا؛ منذ مكتبة بيرل
ويوفر بيرل_get_context()، كل شيء سوف يعمل فقط.

الطريقة الثانية والأكثر فعالية هي استخدام القالب التالي لملف Foo.xs الخاص بك:

#define PERL_NO_GET_CONTEXT /* نريد الكفاءة */
# تضمين "EXTERN.h"
# تضمين "perl.h"
# تضمين "XSUB.h"

STATIC void my_private_function(int arg1, int arg2);

الفراغ ثابت
my_private_function (int arg1، int arg2)
{
dTHX; /* جلب السياق */
... استدعاء العديد من وظائف Perl API ...
}

[... إلخ ...]

الوحدة = حزمة Foo = Foo

/* XSUB النموذجي */

باطل
my_xsub(الأرج)
كثافة العمليات ar
CODE:
my_private_function(arg, 10);

لاحظ أن التغييرين الوحيدين عن الطريقة العادية لكتابة الامتداد هما عملية الإضافة
من "#define PERL_NO_GET_CONTEXT" قبل تضمين رؤوس Perl، متبوعًا بـ
"دثكس؛" إعلان في بداية كل وظيفة ستستدعي Perl API. (سوف
تعرف على الوظائف التي تحتاج إلى ذلك، لأن مترجم لغة C سيشكو من وجود خطأ
معرف غير معلن في تلك الوظائف.) ليست هناك حاجة لإجراء تغييرات على XSUBs
أنفسهم، لأن XS () يتم تعريف الماكرو بشكل صحيح لتمريره في السياق الضمني إذا
الحاجة.

الطريقة الثالثة والأكثر فعالية هي تقليد الطريقة التي يتم بها ذلك داخل لغة بيرل:

#define PERL_NO_GET_CONTEXT /* نريد الكفاءة */
# تضمين "EXTERN.h"
# تضمين "perl.h"
# تضمين "XSUB.h"

/* pTHX_ مطلوب فقط للوظائف التي تستدعي Perl API */
STATIC void my_private_function(pTHX_ int arg1, int arg2);

الفراغ ثابت
my_private_function (pTHX_ int arg1، int arg2)
{
/* دثكس; ليست هناك حاجة هنا، لأن THX هي وسيطة */
... استدعاء وظائف Perl API ...
}

[... إلخ ...]

الوحدة = حزمة Foo = Foo

/* XSUB النموذجي */

باطل
my_xsub(الأرج)
كثافة العمليات ar
CODE:
my_private_function(aTHX_ arg, 10);

لا يتعين على هذا التطبيق مطلقًا جلب السياق باستخدام استدعاء دالة، لأنه كذلك
تم تمريره دائمًا كوسيطة إضافية. اعتمادا على احتياجاتك من البساطة أو الكفاءة،
يمكنك مزج الطريقتين السابقتين بحرية.

لا تقم أبدًا بإضافة فاصلة بعد "pTHX" بنفسك - استخدم دائمًا نموذج الماكرو مع
الشرطة السفلية للوظائف التي تأخذ وسيطات صريحة، أو النموذج بدون الوسيطة
للوظائف التي لا تحتوي على وسائط صريحة.

إذا كان أحدهم يقوم بتجميع لغة Perl باستخدام "-DPERL_GLOBAL_STRUCT"، فستكون هناك حاجة إلى تعريف "dVAR"
إذا كانت المتغيرات العالمية لـ Perl (انظر بيرفارس.ح or globvar.sym) يتم الوصول إليها في الوظيفة
ولا يتم استخدام "dTHX" (يتضمن "dTHX" "dVAR" إذا لزم الأمر). يلاحظ المرء
تحتاج إلى "dVAR" فقط مع تحديد وقت الترجمة المذكور، وإلا فإن Perl global
المتغيرات مرئية كما هي.

وينبغي I do اى شى تختص if I دعوة بيرل تبدأ من متعدد الخيوط؟
إذا قمت بإنشاء مترجمين فوريين في أحد المواضيع ثم تابعت الاتصال بهم في موضوع آخر، فأنت
بحاجة إلى التأكد من تهيئة فتحة التخزين المحلي لمؤشر الترابط (TLS) الخاصة بـ Perl بشكل صحيح
كل من تلك المواضيع.

ستقوم وظيفتا واجهة برمجة التطبيقات "perl_alloc" و"perl_clone" تلقائيًا بتعيين فتحة TLS على
لقد أنشأوا مترجمًا فوريًا، بحيث لا تكون هناك حاجة لفعل أي شيء خاص إذا كان
يتم دائمًا الوصول إلى المترجم في نفس الموضوع الذي قام بإنشائه، لكن هذا الموضوع لم يحدث
إنشاء أو استدعاء أي مترجمين فوريين آخرين بعد ذلك. إذا لم يكن الأمر كذلك، عليك أن تفعل ذلك
قم بتعيين فتحة TLS الخاصة بالخيط قبل استدعاء أي وظائف في Perl API على ذلك
مترجم خاص. يتم ذلك عن طريق استدعاء الماكرو "PERL_SET_CONTEXT" في ذلك
الخيط كأول شيء تفعله:

/* قم بذلك قبل القيام بأي شيء آخر باستخدام some_perl */
PERL_SET_CONTEXT(some_perl);

... مكالمات Perl API الأخرى على some_Perl اذهب هنا ...

Future الخطط و بيرل_IMPLICIT_SYS
تمامًا كما يوفر PERL_IMPLICIT_CONTEXT طريقة لتجميع كل ما يحتاجه المترجم
يعرف عن نفسه ويمرره، وكذلك هناك خطط للسماح للمترجم بذلك
قم بتجميع كل ما تعرفه عن البيئة التي تعمل عليها. تم تمكين هذا مع
الماكرو PERL_IMPLICIT_SYS. يعمل حاليًا فقط مع USE_ITHREADS على نظام التشغيل Windows.

يتيح ذلك القدرة على توفير مؤشر إضافي (يسمى البيئة "المضيفة") لـ
جميع مكالمات النظام. وهذا يجعل من الممكن لجميع عناصر النظام الحفاظ على
الدولة الخاصة، مقسمة إلى سبعة هياكل C. هذه أغلفة رقيقة حول المعتاد
مكالمات النظام (انظر win32/perllib.c) لملف Perl الافتراضي القابل للتنفيذ، ولكن للمزيد
مضيف طموح (مثل الذي سيفعل فرع() مضاهاة) كل العمل الإضافي اللازم ل
سيتم القيام بالتظاهر بأن المترجمين الفوريين المختلفين هم في الواقع "عمليات" مختلفة
هنا.

يعد محرك/مترجم Perl والمضيف كيانين متعامدين. يمكن أن يكون هناك واحد أو
المزيد من المترجمين الفوريين في العملية، وواحد أو أكثر من "المضيفين"، مع حرية الارتباط بينهم
لهم.

داخلي وظائف


جميع وظائف Perl الداخلية التي سيتم كشفها للعالم الخارجي تكون مسبوقة
بواسطة "Perl_" حتى لا تتعارض مع وظائف XS أو الوظائف المستخدمة في البرنامج
حيث تم تضمين لغة Perl. وبالمثل، تبدأ كافة المتغيرات العامة بـ "PL_". (بواسطة
اصطلاحًا، تبدأ الوظائف الثابتة بـ "S_".)

داخل لغة Perl الأساسية (تم تعريف PERL_CORE)، يمكنك الحصول على الوظائف إما باستخدام أو
بدون البادئة "Perl_"، وذلك بفضل مجموعة من التعريفات الموجودة فيها تضمين.ح. لاحظ أن
ينبغي رمز التمديد ليست تعيين "PERL_CORE"؛ يؤدي هذا إلى الكشف عن الأجزاء الداخلية الكاملة لـ Perl، وهو كذلك
من المحتمل أن يتسبب ذلك في كسر XS في كل إصدار جديد من Perl.

الملف تضمين.ح يتم إنشاؤها تلقائيا من تضمين.pl و embed.fnc. تضمين.pl أيضا
ينشئ ملفات رأس النماذج الأولية للوظائف الداخلية، وينشئ ملف
الوثائق والكثير من القطع والقطع الأخرى. من المهم أنه عند إضافة جديد
وظيفة أساسية أو تغيير وظيفة موجودة، يمكنك تغيير البيانات الموجودة في الجدول
embed.fnc أيضًا. فيما يلي نموذج إدخال من هذا الجدول:

Apd |SV** |av_fetch |AV* ar|I32 key|I32 lval

العمود الثاني هو نوع الإرجاع، والعمود الثالث هو الاسم. الأعمدة بعد ذلك هي
الحجج. العمود الأول عبارة عن مجموعة من العلامات:

هذه الوظيفة جزء من واجهة برمجة التطبيقات العامة. يجب أن تحتوي جميع هذه الوظائف أيضًا على "d"،
عدد قليل جدا لا.

p تحتوي هذه الوظيفة على بادئة "Perl_"؛ أي يتم تعريفه على أنه "Perl_av_fetch".

د تحتوي هذه الوظيفة على وثائق تستخدم ميزة "apidoc" والتي سنلقي نظرة عليها في ملف
ثانية. تحتوي بعض الوظائف على "d" وليس "A"؛ المستندات جيدة.

الأعلام الأخرى المتاحة هي:

s هذه دالة ثابتة ويتم تعريفها على أنها "STATIC S_whatever"، وعادةً ما تسمى
ضمن المصادر بـ "مهما كان (...)".

n هذا لا يحتاج إلى سياق مترجم، لذا فإن التعريف لا يحتوي على "pTHX"، وهو كذلك
يتبع أن المتصلين لا يستخدمون "aTHX". (راجع "الخلفية وPERL_IMPLICIT_CONTEXT".)

r هذه الدالة لا تعود أبدًا؛ "النعيق" و"الخروج" والأصدقاء.

f تأخذ هذه الوظيفة عددًا متغيرًا من الوسائط، نمط "printf". قائمة الحجة
يجب أن ينتهي بـ "..."، هكذا:

Afprd |void |croak |const char* pat|...

M هذه الوظيفة جزء من واجهة برمجة التطبيقات للتطوير التجريبي، وقد تتغير أو تختفي
دون سابق إنذار.

o يجب ألا تحتوي هذه الوظيفة على ماكرو توافق لتعريفه، على سبيل المثال، "Perl_parse".
"تحليل". يجب أن يطلق عليه اسم "Perl_parse".

x لا يتم تصدير هذه الوظيفة من قلب Perl.

م ويتم تنفيذ هذا باعتباره الماكرو.

X يتم تصدير هذه الوظيفة بشكل صريح.

هذه الوظيفة مرئية للامتدادات المضمنة في قلب Perl.

ب التوافق الثنائي مع الإصدارات السابقة؛ هذه الوظيفة عبارة عن ماكرو ولكنها تحتوي أيضًا على "Perl_"
التنفيذ (الذي يتم تصديره).

وغيرها
راجع التعليقات الموجودة أعلى "embed.fnc" للآخرين.

إذا قمت بتحرير تضمين.pl or embed.fnc، ستحتاج إلى تشغيل "make regen_headers" لفرض a
إعادة بناء تضمين.ح وغيرها من الملفات التي يتم إنشاؤها تلقائيًا.

منسق الطباعة of الوريد، الأشعة فوق البنفسجية، و نيفادا
إذا كنت تقوم بطباعة IVs أو UVs أو NVS بدلاً من stdio(3) رموز تنسيق النمط مثل
%d، %ld، %f، يجب عليك استخدام وحدات الماكرو التالية لسهولة النقل

IVdf IV بالنظام العشري
UVuf الأشعة فوق البنفسجية في النظام العشري
الأشعة فوق البنفسجية للأشعة فوق البنفسجية في الثماني
UVxf الأشعة فوق البنفسجية في النظام الست عشري
NVef NV %e-like
NVff NV %f مثل
NVgf NV %g مثل

ستهتم هذه بالأعداد الصحيحة ذات 64 بت والزوجي الطويل. على سبيل المثال:

printf("IV is %"IVdf"\n", iv);

سيتم توسيع IVdf إلى التنسيق الصحيح للـ IVs.

لاحظ أن هناك "مضاعفات طويلة" مختلفة: سوف يستخدم Perl كل ما يمتلكه المترجم.

إذا كنت تقوم بطباعة عناوين المؤشرات، فاستخدم UVxf مع PTR2UV()، لا تستخدم %lx
أو %p.

مؤشر إلى عدد صحيح و عدد صحيح إلى المؤشر
لأن حجم المؤشر لا يساوي بالضرورة حجم عدد صحيح، استخدم وحدات الماكرو التالية للقيام بذلك
هذا صحيح.

PTR2UV (المؤشر)
PTR2IV (المؤشر)
PTR2NV (المؤشر)
INT2PTR (نوع المؤشر، عدد صحيح)

فمثلا:

الرابع الرابع = ...;
SV *sv = INT2PTR(SV*, iv);

و

أف * أف = ...;
الأشعة فوق البنفسجية = PTR2UV(av);

استثناء معالجة
هناك عدد من وحدات الماكرو للقيام بمعالجة الاستثناءات الأساسية جدًا في وحدات XS. لديك
لتحديد "NO_XSLOCKS" قبل تضمينها XSUB.h لتتمكن من استخدام وحدات الماكرو هذه:

#تعريف NO_XSLOCKS
# تضمين "XSUB.h"

يمكنك استخدام وحدات الماكرو هذه إذا قمت باستدعاء تعليمات برمجية قد تتعطل، ولكن عليك إجراء بعض التنظيف
قبل إعادة السيطرة إلى بيرل. على سبيل المثال:

dXCPT; /* إعداد المتغيرات الضرورية */

XCPT_TRY_START {
code_that_may_croak();
} XCPT_TRY_END

XCPT_CATCH
{
/* قم بالتنظيف هنا */
XCPT_RETHROW ؛
}

لاحظ أنه يتعين عليك دائمًا إعادة طرح الاستثناء الذي تم اكتشافه. باستخدام هذه
وحدات الماكرو، ليس من الممكن التقاط الاستثناء وتجاهله. إذا كان لديك ل
تجاهل الاستثناء، عليك استخدام وظيفة "call_*".

تتمثل ميزة استخدام وحدات الماكرو المذكورة أعلاه في أنك لا تحتاج إلى إعداد وظيفة إضافية
لـ "call_*"، وأن استخدام وحدات الماكرو هذه أسرع من استخدام "call_*".

مصدر توثيق
هناك جهد مستمر لتوثيق الوظائف الداخلية وإنتاجها تلقائيًا
الأدلة المرجعية منها - Perlapi هو أحد هذه الأدلة الذي يعرض تفاصيل جميع الوظائف
وهي متاحة لكتاب XS. Perlintern هو الدليل الذي تم إنشاؤه تلقائيًا لـ
الوظائف التي ليست جزءًا من واجهة برمجة التطبيقات (API) ومن المفترض أنها مخصصة للاستخدام الداخلي فقط.

يتم إنشاء وثائق المصدر عن طريق وضع تعليقات POD في مصدر C، مثل هذا:

/*
= لapidoc sv_setiv

نسخ عدد صحيح إلى SV معين. لا يتعامل مع السحر "المحدد". يرى
ج.

= قص
*/

يرجى محاولة تقديم بعض الوثائق إذا قمت بإضافة وظائف إلى جوهر Perl.

الى الوراء التوافق
تتغير واجهة برمجة تطبيقات Perl بمرور الوقت. يتم إضافة وظائف جديدة أو واجهات الموجودة
يتم تغيير الوظائف. تحاول الوحدة النمطية "Devel::PPPort" توفير رمز التوافق لـ
بعض هذه التغييرات، لذلك لا يتعين على مؤلفي XS ترميزها بأنفسهم عند الدعم
إصدارات متعددة من بيرل.

يقوم "Devel::PPPort" بإنشاء ملف رأس C ppport.h والتي يمكن أيضًا تشغيلها كبرنامج نصي لـ Perl.
لتوليد ppport.h، يركض:

بيرل -MDevel::PPPort -eDevel::PPPort::WriteFile

إلى جانب التحقق من رمز XS الموجود، يمكن أيضًا استخدام البرنامج النصي لاسترداد التوافق
معلومات لاستدعاءات API المختلفة باستخدام مفتاح سطر الأوامر "--api-info". ل
مثال:

% perl ppport.h --api-info=sv_magicext

للحصول على التفاصيل، راجع "perldoc ppport.h".

يونيكود الدعم


قدم بيرل 5.6.0 دعم Unicode. من المهم للحمالين وكتاب XS أن يفعلوا ذلك
فهم هذا الدعم والتأكد من أن الكود الذي يكتبونه لا يفسد Unicode
البيانات.

ابحث عن is يونيكود, على أي حال؟
في العصور القديمة، الأقل استنارة، اعتدنا جميعًا على استخدام ASCII. معظمنا فعل ذلك، على أية حال.
المشكلة الكبيرة في ASCII هي أنها أمريكية. حسنًا، لا، هذا ليس في الواقع
مشكلة؛ المشكلة هي أنها ليست مفيدة بشكل خاص للأشخاص الذين لا يستخدمون
الأبجدية الرومانية. ما كان يحدث هو أن لغات معينة ستلتصق بنفسها
الأبجدية في النطاق العلوي للتسلسل، بين 128 و 255. بالطبع، نحن بعد ذلك
انتهى الأمر بالكثير من المتغيرات التي لم تكن ASCII تمامًا، والهدف من ذلك
تم فقدان المعيار.

والأسوأ من ذلك، إذا كان لديك لغة مثل الصينية أو اليابانية التي تحتوي على مئات أو
الآلاف من الشخصيات، فلا يمكنك حقًا وضعها في 256 فقط، لذلك كان عليهم القيام بذلك
انس أمر ASCII تمامًا، وقم ببناء أنظمتك الخاصة باستخدام أزواج من الأرقام للإشارة إليها
لشخصية واحدة.

لإصلاح هذه المشكلة، قام بعض الأشخاص بتأسيس شركة Unicode, Inc. وأنتجوا مجموعة أحرف جديدة تحتوي على
جميع الشخصيات التي يمكن أن تفكر فيها وأكثر من ذلك. هناك عدة طرق ل
يمثل هذه الأحرف، والذي يستخدمه Perl يسمى UTF-8. يستخدم UTF-8 أ
عدد متغير من البايتات لتمثيل الحرف. يمكنك معرفة المزيد عن Unicode و
نموذج بيرل لليونيكود في بيرلونيكود.

(على منصات EBCDIC، يستخدم Perl بدلاً من ذلك UTF-EBCDIC، وهو شكل من أشكال UTF-8 تم تكييفه من أجل
منصات EBCDIC. أدناه، نتحدث فقط عن UTF-8. UTF-EBCDIC يشبه UTF-8، لكن
التفاصيل مختلفة. تخفي وحدات الماكرو الاختلافات عنك، فقط تذكر أن
ستختلف الأرقام وأنماط البت المحددة الواردة أدناه في UTF-EBCDIC.)

كيفية يمكن I تعرف a UTF-8 خيط؟
لا يمكنك. وذلك لأن بيانات UTF-8 يتم تخزينها بالبايت تمامًا مثل البيانات غير UTF-8. ال
حرف Unicode 200، (0xC8 بالنسبة للأنواع السداسية عشرية) هو الحرف الكبير E مع اللكنة الخطيرة
ويمثلها البايتين "v196.172". لسوء الحظ، السلسلة غير Unicode
"مركز حقوق الإنسان(196).مركز حقوق الإنسان(172)" يحتوي على تسلسل البايت أيضًا. لذلك لا يمكنك معرفة ذلك بمجرد النظر -
وهذا ما يجعل إدخال Unicode مشكلة مثيرة للاهتمام.

بشكل عام، عليك إما أن تعرف ما الذي تتعامل معه، أو عليك أن تخمن. ال
يمكن لوظيفة API "is_utf8_string" أن تساعد؛ سيخبرك ما إذا كانت السلسلة تحتوي على صالحة فقط
أحرف UTF-8، واحتمال ظهور سلسلة غير UTF-8 تبدو وكأنها UTF-8 صالحة
صغيرة جدًا وبسرعة كبيرة مع زيادة طول السلسلة. على أساس كل حرف على حدة،
سيخبرك "isUTF8_CHAR" ما إذا كان الحرف الحالي في السلسلة صالحًا لـ UTF-8.

كيفية هل UTF-8 مثل يونيكود الشخصيات؟
كما ذكرنا سابقًا، يستخدم UTF-8 عددًا متغيرًا من البايتات لتخزين الحرف.
يتم تخزين الأحرف ذات القيم 0...127 في بايت واحد، تمامًا مثل ASCII الجيد.
يتم تخزين الحرف 128 كـ "v194.128"؛ ويستمر هذا حتى الحرف 191، وهو
"الإصدار 194.191". الآن نفدت البتات لدينا (191 هو الرقم الثنائي 10111111) لذلك نمضي قدمًا؛ شخصية
192 هو "الإصدار 195.128". وهكذا يستمر الأمر، وينتقل إلى ثلاث بايتات عند الحرف 2048. "Unicode
الترميزات" في perlunicode تحتوي على صور لكيفية عمل ذلك.

بافتراض أنك تعرف أنك تتعامل مع سلسلة UTF-8، يمكنك معرفة طول السلسلة الأولى
الحرف الموجود فيه باستخدام الماكرو "UTF8SKIP":

char *utf = "\305\233\340\240\201";
I32 لين؛

len = UTF8SKIP(utf); /* لين هو 2 هنا */
utf += لين;
len = UTF8SKIP(utf); /* لين هو 3 هنا */

هناك طريقة أخرى لتخطي الأحرف في سلسلة UTF-8 وهي استخدام "utf8_hop"، والذي يأخذ
سلسلة وعدد من الأحرف لتخطيها. أنت وحدك فيما يتعلق بفحص الحدود،
على الرغم من ذلك، لذلك لا تستخدمه باستخفاف.

جميع البايتات في حرف UTF-8 متعدد البايت سيكون لها مجموعة بت عالية، لذا يمكنك اختبار ما إذا كان
عليك أن تفعل شيئًا مميزًا مع هذه الشخصية مثل هذا ("UTF8_IS_INVARIANT()"
هو ماكرو يختبر ما إذا كان البايت مشفرًا كبايت واحد حتى في UTF-8):

U8 *utf;
U8 *utf_end; /* 1 خارج المخزن المؤقت المشار إليه بواسطة utf */
الأشعة فوق البنفسجية؛ /* ملاحظة: الأشعة فوق البنفسجية، وليس U8، وليس شار */
سترلين لين؛ /* طول الحرف بالبايت */

إذا (!UTF8_IS_INVARIANT(*utf))
/* يجب التعامل مع هذا على أنه UTF-8 */
uv = utf8_to_uvchr_buf(utf, utf_end, &len);
آخر
/* موافق على التعامل مع هذا الحرف كبايت */
uv = *utf;

يمكنك أيضًا أن ترى في هذا المثال أننا نستخدم "utf8_to_uvchr_buf" للحصول على قيمة
شخصية؛ الوظيفة العكسية "uvchr_to_utf8" متاحة لوضع الأشعة فوق البنفسجية في UTF-8:

إذا (!UVCHR_IS_INVARIANT(uv))
/* يجب التعامل مع هذا على أنه UTF8 */
utf8 = uvchr_to_utf8(utf8, uv);
آخر
/* موافق على التعامل مع هذا الحرف كبايت */
*utf8++ = uv;

أنت يجب قم بتحويل الأحرف إلى UVs باستخدام الوظائف المذكورة أعلاه إذا كنت في موقف ما
حيث يتعين عليك مطابقة أحرف UTF-8 وأحرف غير UTF-8. لا يجوز لك تخطي UTF-8
الشخصيات في هذه الحالة. إذا قمت بذلك، فسوف تفقد القدرة على مطابقة hi-bit
أحرف غير UTF-8؛ على سبيل المثال، إذا كانت سلسلة UTF-8 تحتوي على "v196.172"، وقمت بالتخطي
تلك الشخصية، لا يمكنك أبدًا مطابقة "مركز حقوق الإنسان(200)" في سلسلة غير UTF-8. لذا لا تفعل ذلك!

(لاحظ أنه ليس علينا اختبار الأحرف الثابتة في الأمثلة أعلاه
تعمل الوظائف على أي إدخال UTF-8 جيد التكوين. إنه فقط أنه أسرع لتجنب
وظيفة النفقات العامة عندما لا تكون هناك حاجة إليها.)

كيفية هل بيرل متجر UTF-8 سلاسل؟
حاليًا، تتعامل لغة Perl مع سلاسل UTF-8 والسلاسل غير UTF-8 بشكل مختلف قليلًا. أ
تشير العلامة الموجودة في ملف SV، "SVf_UTF8"، إلى أن السلسلة مشفرة داخليًا كـ UTF-8.
وبدونها، تكون قيمة البايت هي رقم نقطة التشفير والعكس صحيح. هذا العلم فقط
يكون ذا معنى إذا كان SV هو "SvPOK" أو مباشرة بعد التوحيد عبر "SvPV" أو أ
ماكرو مماثل. يمكنك التحقق من هذه العلامة ومعالجتها باستخدام وحدات الماكرو التالية:

SvUTF8(sv)
SvUTF8_on(sv)
SvUTF8_off(sv)

هذه العلامة لها تأثير مهم على معالجة Perl للسلسلة: إذا لم تكن بيانات UTF-8 كذلك
التعبيرات العادية المميزة بشكل صحيح و"الطول" و"substr" ومعالجة السلاسل الأخرى
العمليات سيكون لها نتائج غير مرغوب فيها (خاطئة).

تأتي المشكلة عندما يكون لديك، على سبيل المثال، سلسلة لم يتم وضع علامة عليها كـ UTF-8، و
يحتوي على تسلسل بايت يمكن أن يكون UTF-8 - خاصة عند الجمع بين غير UTF-8 و
سلاسل UTF-8.

لا تنس أبدًا أن علامة "SVf_UTF8" منفصلة عن القيمة PV؛ عليك أن تكون متأكدا
لا يمكنك إيقافه عن طريق الخطأ أثناء التعامل مع SVs. وبشكل أكثر تحديدا، أنت
لا يمكن أن تتوقع القيام بذلك:

SV *SV;
SV *nsv;
سترلين لين؛
شار * ع؛

p = SvPV(sv, len);
فروبنيكات(ع);
nsv = newSVpvn(p, len);

لا تخبرك السلسلة "char*" بالقصة بأكملها، ولا يمكنك نسخ أو إعادة بناء ملف
SV فقط عن طريق نسخ قيمة السلسلة. تحقق مما إذا كان SV القديم يحتوي على علامة UTF8 (بعد القادم
"SvPV")، والتصرف وفقًا لذلك:

p = SvPV(sv, len);
is_utf8 = SvUTF8(sv);
frobnicate(p, is_utf8);
nsv = newSVpvn(p, len);
إذا (is_utf8)
SvUTF8_on(nsv);

في ما ورد أعلاه، تم تغيير وظيفة "frobnicate" الخاصة بك لتكون على علم بما إذا كان أو
لا يتعامل مع بيانات UTF-8، حتى يتمكن من التعامل مع السلسلة بشكل مناسب.

نظرًا لأن مجرد تمرير SV إلى دالة XS ونسخ بيانات SV لا يكفي للقيام بذلك
انسخ إشارات UTF8، والأقل من ذلك هو مجرد تمرير "char *" إلى وظيفة XS.

للحصول على عمومية كاملة، استخدم "DO_UTF8" في الماكرو perlapi لمعرفة ما إذا كانت السلسلة في SV
أن تكون المعالجة مثل UTF-8. يأخذ هذا في الاعتبار ما إذا كان يتم استدعاء وظيفة XS
مصنوعة من ضمن نطاق "استخدام البايتات". إذا كان الأمر كذلك، فإن وحدات البايت الأساسية التي تتكون منها
يجب أن يتم كشف سلسلة UTF-8، بدلاً من الحرف الذي تمثله. ولكن هذه البراغما
يجب أن يتم استخدامه فقط لتصحيح الأخطاء وربما للاختبار منخفض المستوى على مستوى البايت.
ومن ثم فإن معظم أكواد XS لا تحتاج إلى الاهتمام بهذا الأمر، بل بمجالات مختلفة من جوهر لغة Perl
لا حاجة لدعم ذلك.

وهذه ليست القصة كلها. بدءًا من Perl v5.12، السلاسل غير المشفرة
يمكن أيضًا معاملة UTF-8 على أنه Unicode في ظل ظروف مختلفة (راجع "قواعد ASCII مقابل
قواعد Unicode" في perlunicode). هذه مشكلة في الحقيقة فقط للأحرف التي
تتراوح الأعداد الترتيبية بين 128 و255، ويختلف سلوكها بين ASCII وUnicode
القواعد بالطرق التي يهتم بها الكود الخاص بك (راجع "خطأ Unicode"" في perlunicode). هناك
لا توجد واجهة برمجة تطبيقات منشورة للتعامل مع هذا الأمر، لأنها عرضة للتغيير، ولكن يمكنك إلقاء نظرة عليها
رمز "pp_lc" في ص.ج للحصول على مثال لكيفية القيام بذلك حاليا.

كيفية do I تحول a سلسلة إلى UTF-8؟
إذا كنت تخلط بين سلاسل UTF-8 وسلاسل غير UTF-8، فمن الضروري ترقية السلاسل غير UTF-8
سلاسل إلى UTF-8. إذا كان لديك SV، فإن أسهل طريقة للقيام بذلك هي:

sv_utf8_upgrade(sv);

ومع ذلك، لا يجب عليك القيام بذلك، على سبيل المثال:

إذا (!SvUTF8(يسار))
sv_utf8_upgrade(left);

إذا قمت بذلك في عامل تشغيل ثنائي، فسوف تقوم فعليًا بتغيير إحدى السلاسل التي جاءت
في المشغل، وعلى الرغم من أنه لا ينبغي أن يكون ملحوظًا من قبل المستخدم النهائي، إلا أنه يمكن أن يسبب
مشاكل في الكود الناقص.

وبدلاً من ذلك، سيمنحك "bytes_to_utf8" ترميز UTF-8 نسخة من حجة سلسلة لها. هذا
مفيد لتوفير البيانات لإجراء المقارنات وما إلى ذلك، دون الإضرار بالبيانات
SV الأصلي. هناك أيضًا "utf8_to_bytes" للذهاب في الاتجاه الآخر، ولكن من الطبيعي أن يحدث هذا
تفشل إذا كانت السلسلة تحتوي على أي أحرف أعلى من 255 لا يمكن تمثيلها في حرف واحد
بايت.

كيفية do I قارن سلاسل؟
يقوم "sv_cmp" في perlapi و"sv_cmp_flags" في perlapi بإجراء مقارنة معجمية بين اثنين من SV،
والتعامل مع UTF-8ness بشكل صحيح. ومع ذلك، لاحظ أن Unicode يحدد مربي الحيوانات أكثر روعة
آلية التجميع متاحة عبر وحدة Unicode::Collate.

لمقارنة سلسلتين للمساواة/عدم المساواة، يمكنك فقط استخدام "memEQ()" و
"memNE()" كالمعتاد، باستثناء أن السلاسل يجب أن تكون بترميز UTF-8 أو لا تكون بترميز UTF-8.

لمقارنة سلسلتين بشكل غير حساس لحالة الأحرف، استخدم "foldEQ_utf8()" (ليس من الضروري أن تكون السلاسل
لها نفس UTF-8ness).

Is هناك اى شى آخر I حاجة إلى أعرف؟
ليس حقيقيًا. فقط تذكر هذه الأشياء:

· لا توجد طريقة لمعرفة ما إذا كانت السلسلة "char *" أو "U8 *" هي UTF-8 أم لا. ولكن يمكنك
معرفة ما إذا كان سيتم التعامل مع SV على أنه UTF-8 عن طريق استدعاء "DO_UTF8" عليه، بعد التوحيد
باستخدام "SvPV" أو ماكرو مشابه. ويمكنك معرفة ما إذا كان SV هو UTF-8 بالفعل (حتى لو كان
لا ينبغي معاملته على هذا النحو) من خلال النظر إلى علامة "SvUTF8" الخاصة به (مرة أخرى بعد ذلك
تشديده). لا تنس تعيين العلامة إذا كان هناك شيء يجب أن يكون UTF-8. يعامل
العلم كجزء من الكهروضوئية، على الرغم من أنه ليس -- إذا قمت بتمرير الكهروضوئية إلى مكان ما،
تمرير العلم أيضا.

· إذا كانت السلسلة هي UTF-8، دائما استخدم "utf8_to_uvchr_buf" للحصول على القيمة، إلا إذا
"UTF8_IS_INVARIANT(*s)" وفي هذه الحالة يمكنك استخدام *s.

· عند كتابة حرف UV إلى سلسلة UTF-8، دائما استخدم "uvchr_to_utf8"، إلا إذا
"UVCHR_IS_INVARIANT(uv))" وفي هذه الحالة يمكنك استخدام "*s = uv".

· يعد الخلط بين سلاسل UTF-8 وسلاسل غير UTF-8 أمرًا صعبًا. استخدم "bytes_to_utf8" للحصول على سلسلة جديدة
وهو مشفر UTF-8، ثم قم بدمجهما.

Custom تدريب المشغلين والتقنيين


يعد دعم المشغل المخصص ميزة تجريبية تتيح لك تحديد عملياتك الخاصة.
يهدف هذا في المقام الأول إلى السماح ببناء مترجمين فوريين للغات الأخرى في لغة Perl
الأساسية، ولكنه يسمح أيضًا بالتحسينات من خلال إنشاء "عمليات الماكرو" (العمليات التي
تنفيذ وظائف العمليات المتعددة التي عادة ما يتم تنفيذها معًا، مثل "gvsv،
gvsv، إضافة".)

يتم تنفيذ هذه الميزة كنوع تشغيل جديد، "OP_CUSTOM". جوهر بيرل لا "يعرف"
أي شيء خاص بخصوص هذا النوع من العمليات، وبالتالي لن يشارك في أي تحسينات.
وهذا يعني أيضًا أنه يمكنك تحديد عملياتك المخصصة لتكون أي بنية تشغيلية -- أحادية،
ثنائي، قائمة وما إلى ذلك - تريد.

من المهم معرفة ما لن تفعله عوامل التشغيل المخصصة لك. لن يسمحوا لك بإضافة جديد
بناء الجملة إلى بيرل، مباشرة. ولن يسمحوا لك حتى بإضافة كلمات رئيسية جديدة مباشرةً. في الحقيقة،
لن يغيروا الطريقة التي يقوم بها بيرل بتجميع البرنامج على الإطلاق. عليك أن تفعل تلك التغييرات
بنفسك، بعد أن قام بيرل بتجميع البرنامج. يمكنك القيام بذلك إما عن طريق التلاعب بالمرجع
شجرة باستخدام كتلة "التحقق" ووحدة "B::Generate"، أو عن طريق إضافة ثقب الباب المخصص
محسن مع وحدة "التحسين".

عند القيام بذلك، يمكنك استبدال عمليات Perl العادية بعمليات مخصصة عن طريق إنشاء عمليات باستخدام ملف
اكتب "OP_CUSTOM" و"op_ppaddr" لوظيفة PP الخاصة بك. ينبغي تحديد هذا في
رمز XS، ويجب أن يبدو مثل عمليات PP في "pp_*.c". أنت مسؤول عن ضمان
أن العملية الخاصة بك تأخذ العدد المناسب من القيم من المكدس، وأنت
مسؤول عن إضافة علامات المكدس إذا لزم الأمر.

يجب عليك أيضًا "تسجيل" العملية الخاصة بك مع مترجم Perl حتى تتمكن من الإنتاج
خطأ معقول ورسائل التحذير. لأنه من الممكن أن يكون لديك عمليات مخصصة متعددة
ضمن نوع العملية "المنطقية" "OP_CUSTOM"، يستخدم Perl قيمة "o->op_ppaddr" من أجل
تحديد المرجع المخصص الذي يتعامل معه. يجب عليك إنشاء بنية "XOP" لـ
كل ppaddr تستخدمه، قم بتعيين خصائص العملية المخصصة باستخدام "XopENTRY_set"، وقم بالتسجيل
البنية مقابل ppaddr باستخدام "Perl_custom_op_register". قد يكون هناك مثال تافه
يبدو مثل:

ثابت XOP my_xop؛
ثابت OP *my_pp(pTHX);

حذاء طويل:
XopENTRY_set(&my_xop, xop_name, "myxop");
XopENTRY_set(&my_xop, xop_desc, "عملية مخصصة عديمة الفائدة");
Perl_custom_op_register(aTHX_ my_pp, &my_xop);

الحقول المتوفرة في الهيكل هي:

xop_name
اسم قصير للعملية الخاصة بك. سيتم تضمين هذا في بعض رسائل الخطأ، كما سيتم أيضًا
سيتم إرجاعه كـ "$op->name" بواسطة الوحدة B، لذلك سيظهر في مخرجات الوحدة
مثل ب::موجز.

xop_desc
وصف موجز لوظيفة المرجع.

xop_class
أي من هياكل *OP المختلفة التي تستخدمها هذه العملية. ينبغي أن يكون هذا واحدًا من "OA_*"
ثوابت من المرجع السابق. ح، أي

OA_BASEOP
OA_UNOP
OA_BINOP
OA_LOGOP
OA_LISTOP
OA_PMOP
OA_SVOP
OA_PADOP
OA_PVOP_OR_SVOP
يجب تفسير ذلك على أنه ""PVOP"" فقط. "_OR_SVOP" هو لأن الوحيد
يمكن أن يكون "PVOP" الأساسي و"OP_TRANS" في بعض الأحيان "SVOP" بدلاً من ذلك.

OA_LOOP
OA_COP

لا ينبغي استخدام ثوابت "OA_*" الأخرى.

xop_peep
هذا العضو من النوع "Perl_cpeep_t"، والذي يمتد إلى "void (*Perl_cpeep_t)(aTHX_ OP)
*o, OP *oldop)". إذا تم ضبطها، فسيتم استدعاء هذه الوظيفة من "Perl_rpeep" عندما
تتم مواجهة العمليات من هذا النوع بواسطة مُحسِّن ثقب الباب. o هو البروتوكول الاختياري الذي يحتاجه
تحسين؛ com.oldop هو OP السابق المُحسّن، والذي يشير إليه "op_next". o.

يدعم "B::Generate" بشكل مباشر إنشاء عمليات مخصصة بالاسم.

مؤلفون


حتى مايو 1997، كان جيف أوكاموتو يحتفظ بهذه الوثيقة[البريد الإلكتروني محمي]>. إنها
يتم الاحتفاظ بها الآن كجزء من Perl نفسها بواسطة Perl 5 Porters[البريد الإلكتروني محمي]>.

مع الكثير من المساعدة والاقتراحات من دين روهريش، ومالكولم بيتي، وأندرياس كونيج،
بول هدسون، إيليا زاخاريفيتش، بول ماركيز، نيل باورز، ماثيو جرين، تيم بونس،
سبايدر بوردمان، وأولريش فايفر، وستيفن ماكامانت، وجوروسامي ساراثي.

استخدم perlguts عبر الإنترنت باستخدام خدمات onworks.net


خوادم ومحطات عمل مجانية

قم بتنزيل تطبيقات Windows و Linux

أوامر لينكس

Ad




×
الإعلانات
❤️تسوق أو احجز أو اشترِ هنا - بدون تكلفة، مما يساعد على إبقاء الخدمات مجانية.