הבית > תערוכה > תוכן

הצגת רישום או מבנה נתונים, לאיתור מסגרות המחסנית של פונקציות מקוננות בתכנות מחשבים

Apr 22, 2017

ערימת שיחה

במדעי המחשב , ערימת שיחות היא מבנה נתונים מחסנית המאחסן מידע על השגרה הפעילה של תוכנית מחשב . סוג זה של מחסנית ידוע גם ערימת ביצוע , מחסנית תוכנית , מחסנית שליטה , זמן ריצה מחסנית , או מחסנית המכונה , והוא מקוצר לעתים קרובות רק "מחסנית". למרות תחזוקה של מחסנית השיחה חשוב לתפקוד תקין של רוב התוכנות , הפרטים הם בדרך כלל מוסתר ואוטומטי בשפות תכנות ברמה גבוהה . הרבה ערכות הוראה למחשב לספק הוראות מיוחדות עבור מניפולציה ערימות.

ערימת שיחות משמשת למספר מטרות נלוות, אך הסיבה העיקרית לכך היא לעקוב אחר הנקודה שבה כל שגרת פעילות צריכה להחזיר את השליטה כאשר היא מסיימת לבצע. שגרת פעולה פעילה היא זו שנקראה אך עדיין לא השלימה את ביצועה, ולאחר מכן יש להחזיר את השליטה לנקודת השיחה. פעולות כאלה של השגרה עשויות להיות מקוננות לכל רמה (רקורסיבית כמקרה מיוחד), ומכאן מבנה הערימה. אם, למשל, שגרת DrawSquare מכנה שגרתית DrawLine מארבע מקומות שונים, DrawLine חייב לדעת היכן לחזור כאשר ביצועו הושלם. כדי לבצע זאת, הכתובת הנמצאת בהוראת השיחות, כתובת ההחזרה , נדחפת אל ערימת השיחה עם כל שיחה.


תוכן

[ להסתיר ]


תיאור [ לערוך ]

מאז ערימת השיחה מאורגן כערימה , המתקשר דוחף את כתובת החזרה על הערימה, ואת שגרת קרא, כאשר הוא מסיים, מושך או קופץ את כתובת החזרה את מחסנית השיחה ומעביר את השליטה לכתובת זו. אם שגרת הנקראה קוראת לשגרה נוספת, היא תדחוף שוב כתובת חזרה אל מחסנית השיחה, וכן הלאה, כאשר המידע מוערם ופורק כאשר התוכנית מכתיבה. אם הדחיסה צורכת את כל השטח שהוקצה עבור ערימת השיחה, מתרחשת שגיאה הנקראת ' גלישת מחסנית' , בדרך כלל גורמת לקריסה של התוכנית. הוספת ערך השגרה לערימת השיחה נקראת לעתים "מתפתל"; לעומת זאת, הסרת ערכים היא "הרפיה".

בדרך כלל יש רק ערימת שיחות אחת הקשורה לתוכנית ריצה (או ליתר דיוק, עם כל משימה או הליך משנה של תהליך ), אם כי ניתן ליצור ערימות נוספות עבור טיפול אותות או ריבוי משימות משותפות (כמו עם setcontext ). מאחר שיש רק אחד בהקשר חשוב זה, ניתן לכנותו " הערימה" (במשתמע) של המשימה "); עם זאת, בשפת תכנות Forth ערימת הנתונים או מחסנית הפרמטרים נגישה בצורה מפורשת יותר מאשר ערימת השיחה ומכונה בדרך כלל ערימה (ראה להלן).

בשפות תכנות ברמה גבוהה , הפרטים של ערימת השיחה מוסתרים בדרך כלל מהמתכנת. הם מקבלים גישה רק קבוצה של פונקציות, ולא את הזיכרון על הערימה עצמה. זוהי דוגמה של הפשטה . רוב שפות הרכבה , לעומת זאת, דורשות מתכנתים להיות מעורבים עם מניפולציה של הערימה. הפרטים בפועל של הערימה בשפת תכנות תלויים במהדר , במערכת ההפעלה ובמדריך ההוראה הזמין.

פונקציות של ערימת השיחה [ עריכה ]

כפי שצוין לעיל, המטרה העיקרית של ערימת שיחה היא לאחסן את כתובות ההחזרה . כאשר השגרה נקראת, המיקום (כתובת) של ההוראה שבה הוא יכול להמשיך מאוחר יותר צריך להישמר איפשהו. שימוש בערימה כדי לשמור את כתובת החזרה יש יתרונות חשובים על פני מוסכמות קורא חלופי. האחת היא שכל משימה יכולה להיות מחסנית משלה, ולכן השגרת יכולה להיות חזרה, כלומר, יכולה להיות פעילה בו זמנית עבור משימות שונות עושה דברים שונים. יתרון נוסף הוא כי רקורסיה הוא נתמך באופן אוטומטי. כאשר פונקציה מכנה עצמה רקורסיבית, כתובת החזרה צריכה להיות מאוחסנת עבור כל הפעלה של הפונקציה, כך שניתן יהיה להשתמש בה מאוחר יותר כדי לחזור מהפעלת הפונקציה. מבנים מחסנית לספק יכולת זו באופן אוטומטי.

בהתאם לסביבת השפה, מערכת ההפעלה והסביבת המחשב, ערימת שיחות עשויה לשמש למטרות נוספות, כולל לדוגמה:

אחסון נתונים מקומי


לעתים קרובות, השגרה זקוקה למרחב זיכרון לאחסון ערכי משתנים מקומיים , המשתנים הידועים רק במסגרת השיגרת הפעילה ואינם שומרים על ערכים לאחר החזרה. זה לעתים קרובות נוח להקצות מקום לשימוש זה פשוט על ידי הזזת החלק העליון של הערימה על ידי מספיק כדי לספק את החלל. זה מהר מאוד בהשוואה הקצאת זיכרון דינמי , אשר משתמשת שטח גל . שים לב שכל הפעלה נפרדת של השגרה מקבלת מרחב נפרד משלה בערימה עבור המקומיים.


פרמטר עובר


שגרות נדרשות לעתים קרובות כי ערכים עבור הפרמטרים יסופקו להם על ידי הקוד אשר קורא להם, וזה לא נדיר כי שטח הפרמטרים האלה עשויים להיות ערוכים בערימת השיחה. בדרך כלל, אם יש רק מספר קטן של פרמטרים קטנים, מעבדים המעבד ישמש כדי להעביר את הערכים, אבל אם יש יותר פרמטרים מאשר ניתן לטפל בדרך זו, שטח הזיכרון יהיה צורך. ערימת השיחה פועלת היטב כמקום לפרמטרים אלה, במיוחד מאחר שכל קריאה לשגרת משנה, אשר יהיו לה ערכים שונים עבור פרמטרים, תינתן שטח נפרד בערימת השיחה עבור ערכים אלה.


הערכה מחסנית


Operands עבור פעולות חשבון או לוגי ממוקמים לרוב לתוך רושמים ומופעל שם. עם זאת, במצבים מסוימים אופרנדס עשוי להיות מוערמים עד עומק שרירותי, כלומר יותר מאשר רישומים יש להשתמש (זה המקרה של לשפוך לרשום ). ערימת האופראנים האלה, בדומה לזה במחשבון RPN , נקראת ערימת הערכה, ויכולה לתפוס מקום בערימת השיחה.


מצביע למופע הנוכחי


כמה שפות מונחות עצמים (למשל, C + + ), אחסן את המצביע יחד עם ארגומנטים של פונקציה בערימת השיחה בעת הפעלת שיטות. המצביע מצביע על מופע האובייקט הקשור לשיטה שיש להפעיל.


סוגר בהקשר של השגחה


חלק משפות התכנות (למשל, פסקל ועדה ) תומכות בהצהרות של שינויי מקוננות , שאפשרו להן לגשת לקונטקסט של השגרות המקיפות שלהן, כלומר הפרמטרים והמשתנים המקומיים במסגרת השגרה החיצונית. קינון סטטי כזה יכול לחזור על עצמו - פונקציה שהוכרזה בתוך פונקציה שהוכרזה בתוך פונקציה ... היישום חייב לספק אמצעי שבאמצעותו פונקציה הנקראת בכל רמת קינון סטטית מסוימת יכולה להפנות את המסגרת התוחמת בכל רמת קינון המקיפה. בדרך כלל הפניה זו מיושמת על ידי מצביע למסגרת של המופע האחרון שהופעל לאחרונה של הפונקציה המקיפה, הנקרא "קישור downstack" או "קישור סטטי", כדי להבדיל אותו מ "קישור דינמי" שמתייחס למתקשר המיידי ( אשר לא צריך להיות פונקציה הורה סטטי).


במקום קישור סטטי, ההתייחסויות למסגרות הסטטיות התוחמות עשויות להיאסף לתוך מערך של מצביעים הידועים כצג המוצמד לאיתור מסגרת רצויה. עומק קינון לקסיקאלי של שגרתיות הוא קבוע ידוע, כך גודל התצוגה של שגרה קבוע. כמו כן, מספר המכילים scopes לחצות ידוע, המדד לתוך התצוגה הוא קבוע גם. בדרך כלל התצוגה של שגרה ממוקמת מסגרת הערימה שלה, אבל Brough Borroughs B6500 מיושם תצוגה כזו בחומרה שתמכה עד 32 רמות של קינון סטטי.


ערכי התצוגה המציינים טווחים המכילים מתקבלים מהקידומת המתאימה לתצוגת המתקשר. שגרה פנימית החוזרת יוצרת מסגרות שיחה נפרדות לכל קריאה. במקרה זה, כל הקשרים הסטטיים של השגרה הפנימית מצביעים על אותו הקשר שגרתי.


מצב חזרה אחר


לצד כתובת החזרה, בסביבות מסוימות עשויים להיות מצבי מחשב או תוכנה אחרים שיש צורך לשחזרם כאשר שגרת מחזירה. פעולה זו עשויה לכלול דברים כגון רמת הרשאות, מידע על טיפול בחריגים, מצבים אריתמטיים וכן הלאה. במידת הצורך, זה עשוי להיות מאוחסן בערימת השיחה בדיוק כמו כתובת החזרה.


ערימת השיחה הרגילה משמשת עבור כתובת החזרה, המקומיים והפרמטרים (הידועים כמסגרת שיחה ). בסביבות מסוימות יכולות להיות יותר או פחות פונקציות שהוקצו לערימת השיחה. בשפת התכנות Forth , לדוגמה, בדרך כלל רק כתובת ההחזרה, פרמטרים של לולאה סופרת ואינדקסים, ואולי משתנים מקומיים מאוחסנים על ערימת השיחה (אשר בסביבה זו נקראת מחסנית החזרה ), למרות שניתן להציב את כל הנתונים באופן זמני יש שימוש מיוחד לחזור מחסנית טיפול קוד כל עוד הצרכים של שיחות ומחזירים מכובדים; הפרמטרים מאוחסנים בדרך כלל על ערימת נתונים נפרדת או מחסנית פרמטרים , הנקראת בדרך כלל המחסנית במינוח Forth למרות שקיימת ערימת שיחות מכיוון שהיא בדרך כלל גישה מפורשת יותר. כמה Forths יש גם ערימה שלישית פרמטרים נקודה צפה .

מבנה [ לערוך ]

צור פריסת מחסנית שיחה

ערימת שיחה מורכבת ממסגרות ערימה (הנקראות גם רשומות הפעלה או מסגרות הפעלה ). אלה הם תלויות מכונת ABI- תלוי נתונים מבנים המכילים מידע מצב שגרה. נתונים אלה מכונה לעתים כ CFI (Call Frame Information). [1] כל מסגרת ערימה מתאימה לשיחה לשגרה שעדיין לא הסתיימה עם החזרה. לדוגמה, אם שגרת ששמה DrawLine פועלת כעת, לאחר שהיא נקראה על ידי שגרת DrawSquare , החלק העליון של ערימת השיחה עשוי להיות מונח כמו בתמונה מימין.

תרשים כזה יכול להיות מצויר בכל כיוון כל עוד המיקום של הדף, ולכן כיוון של מחסנית הצמיחה, הוא הבין. יתר על כן, באופן עצמאי, ארכיטקטורות שונות לגבי השאלה אם ערימות שיחה לגדול כלפי כתובות גבוהות יותר או כלפי כתובות נמוכות יותר. ההיגיון של הדיאגרמה אינו תלוי בבחירת הפנייה.

מסגרת הערימה בחלק העליון של המחסנית היא לשגרת ביצוע הנוכחית. מסגרת הערימה כוללת בדרך כלל לפחות את הפריטים הבאים (בסדר דחיפה):

  • הארגומנטים (ערכי הפרמטרים) עברו לשגרה (אם בכלל);

  • את הכתובת לחזור אל המתקשר שגרתית (למשל במסגרת DrawLine מחסנית, כתובת לתוך קוד של DrawSquare ); ו

  • רווח עבור המשתנים המקומיים של השגרה (אם בכלל).

מחסנית ומסגרת מצביעים [ עריכה ]

כאשר ערימת מסגרת גדלים יכול להיות שונה, כגון בין פונקציות שונות או בין invocations של פונקציה מסוימת, popping מסגרת מחוץ לערימה אינו מהווה ירידה קבועה של המצביע מחסנית . בחזרת פונקציה, מצביע המחסנית משוחזר במקום זה למצביע המסגרת , הערך של מצביע המחסנית ממש לפני שהפונקציה נקראה. כל מסגרת מחסנית מכילה מצביע מחסנית לחלק העליון של המסגרת מיד מתחת. מחוון המחסנית הוא רישום משותף המשתנה בין כל ההקצאות. מצביע מסגרת של הפניה נתונה של פונקציה הוא עותק של מצביע המחסנית כפי שהיה לפני שהפונקציה הופעלה. [2]

ניתן להגדיר את מיקומם של כל שאר השדות במסגרת יחסית או לחלק העליון של המסגרת, כמו קיזוזים שליליים של מצביע המחסנית, או יחסית לחלק העליון של המסגרת למטה, כמחיצות חיוביות של מצביע המסגרת. המיקום של מצביע המסגרת עצמו חייב להיות מוגדר כקיזוז שלילי של מצביע המחסנית.

אחסון הכתובת למסגרת המתקשר [ לערוך ]

ברוב המערכות יש למסגרת ערימה שדה המכיל את הערך הקודם של מסמן המצביע למסגרת, הערך שהיה לו בזמן שהמתקשר ביצע. לדוגמה, מסגרת המחסנית של DrawLine תהיה בעלת מיקום זיכרון המחזיק את ערך המצביע של המסגרת ש- DrawSquare משתמש בו (לא מוצג בתרשים לעיל). הערך נשמר עם הכניסה לשגרת השיקום ומשוחזר עם החזרה. לאחר שדה כזה במיקום ידוע במסגרת הערימה מאפשר קוד לגשת לכל מסגרת ברצף מתחת למסגרת השגרה הנוכחית, וגם מאפשר לשגרה לשחזר בקלות את המצביע מסגרת למסגרת של המתקשר , ממש לפני שהוא חוזר.

נהלים מקוננים בקססה [ לערוך ]

מידע נוסף: פונקציה מקוננת ומשתנה לא מקומי

שפות תכנות התומכות בשגרות משנה מקוננות יש גם שדה במסגרת השיחה שמצביע על מסגרת המחסנית של ההפעלה האחרונה של הפרוצדורה המקרוב ביותר את ה- callee, כלומר, ההיקף המיידי של ה- callee. זה נקרא קישור גישה או קישור סטטי (כפי שהוא עוקב אחר קינון סטטי במהלך שיחות דינמיות ו רקורסיבית) ומספק את שגרת (כמו גם כל שגרות אחרות זה עשוי לעורר) גישה לנתונים המקומיים של שלה encapsulating שגרות בכל קינון רָמָה. ארכיטקטורות מסוימות, מהדרים או מקרים אופטימיזציה לאחסן קישור אחד עבור כל רמה מצרף (לא רק את המקיף מיד), כך שגידים מקוננות עמוק כי גישה לנתונים רדודים לא צריך לעבור כמה קישורים; אסטרטגיה זו נקראת לעתים קרובות "תצוגה". [3]

ניתן לבצע אופטימיזציה של קישורים גישה כאשר פונקציה פנימית אינה ניגשת לכל הנתונים המקומיים (שאינם קבועים) באנקסולציה, כמו במקרה של פונקציות טהורות המתקשרות רק באמצעות ארגומנטים וערכי החזרה, לדוגמה. כמה מחשבים היסטוריים, כגון המערכות הגדולות של Borrough , היו בעלי "רישומי תצוגה" מיוחדים לתמיכה בפונקציות מקוננות, ואילו מהדרים עבור רוב המכונות המודרניות (כגון x86 בכל מקום) פשוט שומרים כמה מילים על הערימה עבור המצביעים, לפי הצורך.

חפיפה [ עריכה ]

למטרות מסוימות, מסגרת הערימה של השגרה ושל המתקשר שלה יכולה להיחשב לחפיפה, החפיפה המורכבת מהאזור שבו מועברים הפרמטרים מהמתקשר אל ה- callee. בסביבות מסוימות, המתקשר דוחף כל טיעון על הערימה, ובכך להרחיב את מסגרת הערימה שלה, ואז מעורר את callee. בסביבות אחרות, למתקשר יש אזור preallocated בחלק העליון של מסגרת הערימה שלו כדי להחזיק את הארגומנטים שהוא מספק לשגרות אחרות שהוא קורא. אזור זה מכונה לפעמים אזור ארגומנטים יוצאים או אזור הסבר . לפי גישה זו, גודל השטח מחושב על ידי המהדר להיות הגדול ביותר הנדרש על ידי כל שגרת שנקרא.

השתמש [ עריכה ]

התקשר לאתר עיבוד [ לערוך ]

בדרך כלל קוראים את מניפולציה הדרוש באתר של קריאה לשגרת היא מינימלית (וזה טוב שכן לא יכול להיות הרבה אתרי שיחה עבור כל שגרת להיקרא). הערכים של הארגומנטים עצמם מוערכים באתר השיחה, כיוון שהם ספציפיים לשיחה מסוימת, או נדחפים לערימה או מועברים לרשומות, כפי שנקבע על ידי ועידת השיחות המשומשת. ההוראה להתקשרות בפועל, כגון "סניף וקישור", מתבצעת בדרך כלל כדי להעביר את השליטה לקוד של שגרת המטרה.

עיבוד השגרה כניסה [ לערוך ]

בשגרה הקרובה, הקוד הראשון שבוצע הוא בדרך כלל נקרא פרולוג השגרה , שכן היא עושה את הצורך housekeeping לפני קוד עבור הצהרות של השגרה הוא התחיל.

הפרולוג יהיה בדרך כלל לשמור את כתובת החזרה שנשאר ברשומה על ידי הוראה להתקשר על ידי לחיצה על הערך על ערימת השיחה. באופן דומה, ניתן לטעון את ערכי המחוון הנוכחי של המצביע ו / או המסגרת. לחלופין, כמה ארכיטקטורות קבוצת ההוראה מספקות באופן אוטומטי פונקציונליות דומה כחלק מהפעולה של הוראת השיחות עצמה, ובסביבה כזו אין צורך בפרולוג.

אם נעשה שימוש במצבי מסגרת, הפרולוג בדרך כלל יקבע את הערך החדש של מצביע המסגרת מתוך מצביע המחסנית. ניתן להקצות שטח על הערימה עבור משתנים מקומיים על ידי שינוי מצטבר של מצביע המחסנית.

שפת תכנות Forth מאפשרת סלילה מפורשת של ערימת השיחה (הנקראת שם "מחסנית החזרה").

חזור עיבוד [ לערוך ]

כאשר השגרה מוכנה לחזור, היא מבצעת אפילוג המתיר את צעדי הפרולוג. זה בדרך כלל לשחזר ערכי לרשום שמור (כגון ערך המצביע מסגרת) מתוך מסגרת הערימה, לפוצץ את כל מסגרת מחסנית את הערימה על ידי שינוי ערך המצביע מחסנית, ולבסוף סניף להנחיות בכתובת החזרה. תחת רבים מוסכמות קורא את הפריטים popped את ערימת על ידי אפילוג לכלול את ערכי הטיעון המקורי, ובמקרה זה בדרך כלל אין עוד מניפולציות מחסנית כי צריך להיעשות על ידי המתקשר. עם כמה מוסכמות קורא, עם זאת, האחריות של המתקשר להסיר את הטיעונים מן הערימה לאחר החזרה.

מחיקת [ עריכה ]

החזרה מהפונקציה הנקראת תקפיץ את המסגרת העליונה של הערימה, ואולי תשאיר ערך החזרה. הפעולה הכללית יותר של popping אחד או יותר מסגרות מחוץ לערימה כדי לחדש את ביצוע במקום אחר בתוכנית נקרא ערימת הפתיחה חייב להתבצע כאשר המבנים הלא מקומיים המשמשים משמשים, כגון אלה המשמשים לטיפול יוצא מן הכלל . במקרה זה, מסגרת הערימה של פונקציה מכילה רשומה אחת או יותר המפרטת את מטפלי החריגים. כאשר נזרק חריג, הערימה מנותקת עד שהמטפל נמצא כי הוא מוכן לטפל (לתפוס) את סוג החריג שנזרק.

בשפות מסוימות יש מבני בקרה אחרים הדורשים שחרור כללי. פסקל מאפשר הצהרה גלובלית goto להעביר שליטה מתוך פונקציה מקוננת לתוך פונקציה חיצונית בעבר. פעולה זו מחייבת את ערימת להיות unound, הסרת מסגרות ערימה רבים ככל הנדרש כדי לשחזר את ההקשר הנכון להעביר את השליטה על הצהרת היעד בתוך הפונקציה החיצונית המקיפה. באופן דומה, C יש את פונקציות longjmp ו longjmp לפעול כפי gotos המקומי. Common Lisp מאפשר שליטה על מה קורה כאשר מחסנית הוא unound באמצעות שימוש מיוחד unwind-protect מפעיל מיוחד.

בעת החלת המשכו , הערימה היא (באופן הגיוני) להתיר ולאחר מכן rewound עם ערימת ההמשך. אין זו הדרך היחידה ליישם את המשכיות; למשל, באמצעות מספר רב של ערימות מפורשות, יישום של המשך יכול פשוט להפעיל את הערימה שלו רוח ערך להיות עבר. שפת התכנות Scheme מאפשרת שרירים שרירותיים להתבצע בנקודות מסוימות על "הרפיה" או "rewinding" של ערימת הבקרה בעת המשך מופעלת.

פיקוח [ לערוך ]

ראה גם: פרופיל (תכנות מחשבים)

לעיתים ניתן לבדוק את ערימת השיחה כאשר התוכנית פועלת. תלוי איך התוכנית כתבה מלוקט, את המידע על מחסנית ניתן להשתמש כדי לקבוע ערכי ביניים ו פונקציה עקבות השיחה. זה נעשה כדי ליצור בדיקות אוטומטיות בסדר גרגר, [4] ובמקרים כמו רובי ו Smalltalk, ליישם משכורות מדרגה ראשונה. לדוגמה, מאתר הבאגים של GNU (GDB) מיישם בדיקה אינטראקטיבית של ערימת השיחות של תוכנית ריצה, אך מושהית, C. [5]

נטילת דוגמיות זמן קבוע של ערימת השיחות יכולה להיות שימושית בפרופילינג הביצועים של תוכניות, כי אם מצביע של השגרה מופיע על הנתונים מחסנית הדגימה נתונים פעמים רבות, סביר להניח צוואר בקבוק קוד צריך להיבדק על בעיות ביצועים.

אבטחה [ עריכה ]

מאמר ראשי: מחסנית הצפת מאגר

בשפה עם מצביעים חופשיים או כותבי מערך שאינם נבדקים (כגון ב- C), ערבוב נתוני זרימת הבקרה המשפיעים על ביצוע קוד (כתובות ההחזרה או מצביעי המסגרת השמורים) ונתוני תוכנה פשוטים (פרמטרים או ערכי החזרה) ) בערימת שיחה הוא סיכון אבטחה, אולי לנצל באמצעות ערימת הצפת מאגר כמו הסוג הנפוץ ביותר של הצפת מאגר .

אחד ההתקפות האלה כרוך מילוי מאגר אחד עם קוד הפעלה שרירותי, ולאחר מכן על גדותיו או מאגר אחר כדי להחליף כמה כתובת החזרה עם ערך שמצביע ישירות על קוד ההפעלה. כתוצאה מכך, כאשר הפונקציה חוזרת, המחשב מבצע את הקוד. סוג זה של התקפה יכול להיות חסום בקלות עם W ^ X. התקפות דומות יכולות להצליח גם עם הגנה של X ^ X, כולל התקפת החזרה ל- libc או ההתקפות שמקורן בתכנות מוכווני חזרה . הצעות שונות הוצעו, כגון אחסון מערכים במיקום נפרד לחלוטין מערימת החזרה, כמו במקרה של שפת תכנות Forth. [6]