המצגת נטענת. אנא המתן

המצגת נטענת. אנא המתן

תורת הקומפילציה תרגול 9: תרגום לקוד ביניים

מצגות קשורות


מצגת בנושא: "תורת הקומפילציה תרגול 9: תרגום לקוד ביניים"— תמליל מצגת:

1 תורת הקומפילציה תרגול 9: תרגום לקוד ביניים
עודכן: סמסטר אביב 2012

2 מבנה סכמתי של קומפיילר עד כה ראינו: בפועל: Back-end Front-end ניתוח
לקסיקלי תחבירי סמנטי backend ניתוח לקסיקלי תחבירי סמנטי backend אופטימיזציה שפת ביניים Back-end Front-end

3 שפת ביניים מדוע לא לתרגם ישר לשפת היעד?
פיתוח מהיר יותר של קומפיילר למערכת חדשה נדרש לכתוב מחדש רק את ה Back-end. פיתוח אופטימיזציות כלליות. שפת ביניים איתה נעבוד בקורס: שפת הרביעיות דומה מאד לשפת אסמבלר. סדרה של פקודות מהצורה x := y OP z

4 שפת ביניים (המשך) נעבוד עם 4 סוגי פקודות בלבד: t1 := t2 + t3
פעולה אריתמטית: קפיצה לא-מותנית: קפיצה מותנית: תווית: קיימות פקודות רבות נוספות.... t1 := t2 + t3 goto label if t1 relop t2 goto label label:

5 דוגמה a = b + c + d t1 := b + c t2 := t1 + d a := t2 מדוע צריך את t2?

6 טעויות נפוצות דברים שאינם קוד ביניים: if … else …
if (x > 1 && y > 1) goto … התנאי בקפיצה אינו מורכב. נראה ייצוג חלופי בשפת ביניים לשני המקרים הללו. x = 1000 goto x ניתן לקפוץ רק לתוויות קבועות.

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

8 פונקציות לפריסת קוד פונקציות עזר:
newtemp(): יוצרת משתנה זמני חדש (בעל מזהה ייחודי), כולל הכנסתו לsymbol table. newlabel(): מחזירה תווית חדשה. gen(string) : מקבלת מחרוזת שמייצגת פקודות ומייצרת את הפקודות בשפת הביניים.

9 שיטות לייצור קוד נציג 2 שיטות לייצור קוד:
שיטה ראשונה: הקוד נאגר בתכונה סמנטית בשם code: לכל משתנה בדקדוק יש תכונה סמנטית בשם code, אשר אוגרת את הקוד שנוצר מהמשתנים שכבר נגזרו. בסוף הניתוח התכונה code של המשתנה התחילי מכילה את כל הקוד של התוכנית.

10 שיטה ראשונה ליצירת קוד - דוגמה
דוגמה: תרגום ביטויים אריתמטיים נגדיר למשתנה E את התכונות code ו-place (place יכיל את המשתנה הזמני אליו נשמר ערך הביטוי). E  E1 + E2 { E.place = newtemp(); E.code = E1.code || E2.code || gen (E.place ‘:=‘ E1.place ‘+’ E2.place); } יצירת מקום לתוצאה יצירת הקוד: t1  E1 t2  E2 t3 := t1 + t2

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

12 שיטה שנייה ליצירת קוד - דוגמה
דוגמה: תרגום ביטויים אריתמטיים ל-E נגדיר תכונה place (אין צורך בתכונת code). הפונקציה emit מדפיסה פקודה ל-buffer. E  E1 + E2 { E.place = newtemp(); emit(E.place || “:=“ || E1.place || “+” || E2.place); } היכן הקוד של E1 ו-E2?

13 השוואה בין שתי השיטות בשיטה 1 ניתן לקבוע את הסדר של קטעי הקוד ובשיטה 2 – לא ניתן למשל: E.code = E2.code || E1.code || E.place || “:=“ || E1.place || “+” || E2.place; במקום: E.code = E1.code || E2.code || שיטה 2 פשוטה ומהירה יותר אין שרשורי קוד.

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

15 הקושי כאשר מתרגמים מבנה בקרה, יעדי הקפיצות לא תמיד ידועים.
לדוגמה: if B then S1 else S2 לכאורה, יש יותר מנקודת יציאה אחת: יש לבצע קטע קוד אחד במקרה והתנאי הבוליאני מתקיים, או קטע קוד אחר במקרה והתנאי אינו מתקיים. איך המנתח יידע את מי משני קטעי הקוד עליו למקם מיד אחרי קטע הקוד לבדיקת התנאי B?

16 פתרון לבעיית if B then S1 else S2
קטע הקוד שאחריו ימשיך לביצוע של S1 או S2 על פי ערכו של המשתנה הזמני. קטע הקוד השקול בשפת ביניים, לאחר תרגום פשוט: code that evaluates some_expression into t13 if t13==0 goto L54 code for some_code_1 goto L55 L54: code for some_code_2 L55:

17 דוגמה- הקוד לשיערוך הביטוי הבוליאני
E -> E1 '>' E2 label tmplabel = newlabel(); E.place = newtemp(); E.code = E1.code || E2.code || gen(E.place '= 0') || gen('if' E1.place '<=' E2.place 'goto' tmplabel) || gen(E.place '= 1') || gen(tmplabel ':');

18 דוגמה- תרגום פשוט עבור פקודת תנאי
E -> E1 '>' E2 label tmplabel = newlabel(); E.place = newtemp(); E.code = E1.code || E2.code || gen(E.place '= 0') || gen('if' E1.place '<=' E2.place 'goto' tmplabel) || gen(E.place '= 1') || gen(tmplabel ':'); S -> if E then S1 else S2 label falseLabel = newlabel(), endLabel = newlabel(); S.code = E.code || gen ('if' E.place '== 0' 'goto' falseLabel) || S1.code || gen ('goto' endLabel) || gen (falseLabel ':') || S2.code || gen (endLabel ':');

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

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

21 שיטת התוויות הנורשות כל תווית של נקודת יציאה אפשרית תישמר בתכונה נורשת : לדוגמה: B.false, B.true ברגע שנסיים לתרגם את כל המבנה הבוליאני, נדע רק אז לחשב את התכונות. אין צורך לחשב מפורשות את ערכי התנאים הבוליאניים (כפי שחישבנו ערך ביטוי בוליאני למשתנה זמני בתרגום פשוט). התווית אליה יש להמשיך אם הביטוי השתערך להיות T התווית אליה יש להמשיך אם הביטוי הוא F

22 דוגמה – תרגום משפט if מורכב
S → if B then S1 else S2 B → B1 or B2 B → E1 ’>’ E2 התכונות (הנורשות): B.false : התווית אליה תעבור התוכנית במקרה שערך הביטוי הוא false. B.true: התווית אליה תעבור התוכנית אם ערך הביטוי הוא true. S.next: התווית אליה נעבור בסיום הפקודה S.

23 דוגמה – תרגום משפט if מורכב
S → if B then S1 else S2 B → B1 or B2 B → E1 ’>’ E2 התכונות (הנורשות): B.false : התווית אליה תעבור התוכנית במקרה שערך הביטוי הוא false. B.true: התווית אליה תעבור התוכנית אם ערך הביטוי הוא true. S.next: התווית אליה נעבור בסיום הפקודה S.

24 דוגמה – תרגום משפט if מורכב
סכימת התרגום: S → if B then S1 else S2 { B.true = newlabel(); B.false = newlabel(); S1.next = S.next S2.next = S.next S.code = B.code || gen (B.true ':') || S1.code || gen ('goto' S.next) || gen (B.false ':') || S2.code; }

25 המשך הדוגמה – הקוד עבור הביטוי הבוליאני
B → E1 ’>’ E2 E1.code E2.code if (E1.place > E2.place) goto B.true goto B.false תזכורת: זהו המשתנה הזמני שהוקצה לביטוי (למשל מיקום במחסנית) B → E1 ’>’ E2 { B.code = E1.code || E2.code || gen (‘if’ E1.place ‘>’ E2.place ‘goto’ B.true) || gen (‘goto’ B.false) ; }

26 המשך הדוגמה – הקוד עבור הביטוי הבוליאני
B → B1 or B2 B1.code B2.code false true true B1.false: false B → B1 or B2 { B1.true = B.true; B2.true = B.true; B1.false = newlabel(); B2.false = B.false; B.code = B1.code || gen (B1.false ‘:’) || B2.code; }

27 המשך הדוגמה – הקוד עבור הביטוי הבוליאני
B → B1 or B2 B1.code B2.code false true true B1.false: false הערות: הבדיקות מבוצעת בשיטת lazy evaluation : ברגע שהתשובה ידועה מפסיקים לחשב. המשמעות היא כמו של האופרטור || ולא כמו האופרטור | סדר החישוב לא ידוע מראש, והפעולות של אותו כלל לא בהכרח מבוצעות ברצף.

28 שיטת התוויות הנורשות - חסרונות
לא מתאימה לניתוח סמנטי בזמן bottom-up השתמשנו בתכונות נורשות. כדי לעבוד עם תכונות נורשות ב bottom-up יש: לבנות את עץ הגזירה. למיין טופולוגית את חישובי התכונות על פי התלויות (לכל תכנית מחדש). רק בסוף ניתן לחשב את התכונות ע"י מעבר נוסף על העץ. בזבזני מאוד בזמן ריצה.

29 שיטת התוויות הנורשות - חסרונות
הפיתרון: להמנע מהורשת תוויות! אבל...משתנה לא יכול לדעת באופן עצמאי לאן לקפוץ. המנעות מהורשה תחייב היפוך תפקידים: במקום שהאבא יגיד לבן: נקודת היציאה שלך exit מופנית לתווית label, הבן יגיד לאב: אם הייתי יודע לאן exit מופנה, הייתי רושם ערך זה "כאן, כאן, ... וכאן". ברגע שתחליט לאן exit מופנה, אנא מלא את כל החורים שהשארתי בתווית עליה החלטת! זוהי שיטת backpatching – בתרגול הבא.


הורד את "ppt "תורת הקומפילציה תרגול 9: תרגום לקוד ביניים

מצגות קשורות


מודעות Google