תורת הקומפילציה 236360
Download
1 / 63

תורת הקומפילציה 236360 הרצאה 9 שפות ביניים Intermediate Languages/Representations - PowerPoint PPT Presentation


  • 177 Views
  • Uploaded on

תורת הקומפילציה 236360 הרצאה 9 שפות ביניים Intermediate Languages/Representations. Aho, Sethi and Ullman – Chapter 6 Cooper and Torczon – Chapter 5. יצירת קוד ביניים. syntax analysis. syntax tree. semantic analysis. decorated syntax tree. intermediate code generator. intermediate code.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' תורת הקומפילציה 236360 הרצאה 9 שפות ביניים Intermediate Languages/Representations' - vinaya


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

תורת הקומפילציה 236360הרצאה9

שפות ביניים

Intermediate Languages/Representations

Aho, Sethi and Ullman – Chapter 6

Cooper and Torczon – Chapter 5


יצירת קוד ביניים

syntax analysis

syntax tree

semantic analysis

decorated syntax tree

intermediate code generator

intermediate code

machine independent optimizations

intermediate code

code generator


חשיבות קוד הביניים

  • שימוש בשיטות אופטימיזציה שאינן תלויות במכונה מסויימת

  • אפשרות לייצר קוד עבור מכונות שונות באמצעות אותו front end

  • שימוש באותו back end עבור שפות שונות – מספר front ends

  • אם כתבנו mfront-ends ו-nback ends, אז ניתן לשלב אותם ולקבל n*m קומפיילרים.

C

Java

Pascal

C#

Intermediate Language

Cray

PowerPC

Intel


Intermediate representation
ייצוג ביניים – intermediate representation

  • ייצוגים אפשריים

    • syntax tree

    • postfix notation

    • three address code – זו הצורה שאנו נבחר לעבוד איתה.

      • שני אופרנדים ותוצאה אחת.

  • בד"כ עובדים בשני שלבים:

    • תרגום מונחה דקדוק יוצר עץ ניתוח תחבירי + סימונים בצמתים

    • את העץ מתרגמים ל- three address code

  • נדבר ראשית על ייצוג העץ, לפעמים נשתמש ב- DAG(Directed Acyclic Graph) במקום בעץ.


Decorated syntax trees dags postfix
שלושה ייצוגים אפשריים:decorated syntax trees, DAGs, ו-postfix

  • נתון: a := b * –c + b * –c

  • ייצוג כ- DAG

ייצוג כעץ

ייצוג ב- postfix

a b c uminus * b c uminus * + assign


דוגמה:תרגום מונחה דקדוק ליצירת עץ מעוטר

  • פונקציות עזר

    • mkleaf – יצירת עלה

    • mkunode – יצירת צומת חדש עבור אופרטור אונרי

    • mknode – יצירת צומת חדש עבור אופרטור בינארי

    • id.place – מצביע לטבלת הסמלים

  • הערה – אפשר להחליף את mkleaf, mkunode, ו- mknode בפונקציות המחזירות מצביע לצמתים קיימים על מנת ליצור DAG


assign

*

*

id

a

id

id

b

b

+

uminus

uminus

id

id

c

c

ייצוג בזיכרון של עץ מעוטר

a := b * –c + b * –c


Three address code

אופרטור

3 הכתובות

three address code

  • אחרי שבונים את העץ, צריך לתרגם לשפת הביניים שבחרנו.

  • אנו נעבוד עם three-address-code.

  • הצורה הכללית של פקודה:

    x := y op z

  • x, y, ו-z הם 3 שמות, קבועים, או משתנים זמניים שנוצרו ע"י הקומפיילר.

  • op הוא אופרטור כלשהו.

  • האופרטורים שנשתמש בהם יהיו פשוטים, כך שיהיה קל לעבור מהם לשפת מכונה.


Three address code1

assign

assign

a

+

a

+

*

*

*

b

unimus

b

unimus

b

unimus

c

c

c

t1

:=

– c

t1

:=

– c

t2

:=

b * t1

t2

:=

b * t1

t3

:=

– c

t3

:=

t2 + t2

t4

:=

b * t3

a

:=

t3

t5

:=

t2 +t4

a

:=

t5

three address code


קוד ביניים – סוגי המשפטים

relop = relational op (==, >=, etc.)

n = actual number of parameters

קריאה לפרוצדורה:

param x1

param xn

call p,n


איך בוחרים אופרטורים?

  • הבחירה של אוסף פקודות מתאים היא חשובה.

  • אוסף מצומצם:

    • קל ליצור קוד מכונה,

    • הקוד יהיה פחות יעיל, ומעמסה גדולה יותר תיפול על ה- optimizer

    • הקוד יהיה ארוך והטיפול בו יהיה מסורבל

    • אי ניצול יכולות של מכונות חכמות

  • אופרטורים רבים:

    • קוד יותר יעיל אך קשה יותר לייצרו וממנו קשה לייצר קוד עבור מכונות פשוטות.


יצירת קוד ביניים בעל 3 כתובות על ידי תרגום מונחה דקדוק

ככלל, נניח bottom-up parsing כך שדברים מחושבים לפני שמשתמשים בתוצאת החישוב.

השיטה – שימוש במשתנים זמניים

  • S.code (או E.code)– תכונה המכילה את הקוד הנוצר עבור S (או E).

  • E.var – שם של משתנה שעתיד להכיל את הערך של E

  • newtemp – פונקציה המחזירה שם של משתנה חדש


יצירת קוד ביניים בעל 3 כתובות על ידי תרגום מונחה דקדוק


While labels

production ידי תרגום מונחה דקדוק

semantic rule

S →while E do S1

S.begin := newlabel ;

S.after := newlabel ;

S.code := gen ( S.begin ' : ' ) || E.code ||

gen ( ' if ' E.var ' = '' 0 '' goto ' S.after ) ||

S1.code || gen ( ' goto ' S.begin ) || gen (S.after ' : ' )

פסוק while:דוגמא לשימוש בתוויות (labels)

S →while E do S1

  • נוסיף תכונות למשתנים, ותוויות.

  • newlabel– פונקציה היוצרת תווית חדשה

  • S.begin – תווית המסמנת את תחילת הקוד

  • S.after – תווית המסמנת את סוף הקוד

  • 0 – מייצג את false


3 address code

ידי תרגום מונחה דקדוק

מצביעים לטבלת הסמלים

op

arg 1

arg 2

result

(0)

uminus

c

t1

(1)

*

b

t1

t2

(2)

uminus

c

t3

(3)

*

b

t3

t4

(4)

+

t2

t4

t5

(5)

=:

t5

a

מבנה נתונים לייצוג של 3-address code:

  • ייצוג סטנדרטי הוא ע"י רביעיות כך שכל שורה נכתבת לתוך משתנה זמני.

    op, arg1, arg2, result

  • יתרון:פשוט + אין בעיה להעתיק ולהזיז קטעי קוד (וזה חשוב לאופטימיזציות).

  • עלות – מחייב לשמור את ה- temporaries בטבלת הסמלים

t1 = - c

t2 = b * t1

t3 = - c

t4 = b * t3

t5 = t2 * t4

a = t5


3 address code1

ידי תרגום מונחה דקדוק

op

arg 1

arg 2

מצביעים לטבלת הסמלים או למספר הסידורי של השורה המחשבת את הערך

(0)

uminus

c

(1)

*

b

(0)

(2)

uminus

c

(3)

*

b

(2)

(4)

+

(1)

(3)

(5)

assign

a

(4)

op

op

arg 1

arg 1

arg 2

arg 2

(0)

(0)

[ ] =

= [ ]

x

y

i

i

(1)

(1)

assign

assign

x

(0)

(0)

y

x [ i ] := y

x := y [ i ]

ייצוג נוסף של 3-address code

  • שלשות : op, arg1, arg2(התוצאה מובנת כמספר השורה)

  • אין צורך ב- result

  • אבל: אי אפשר להזיז קוד +פעולה טרנרית כמו x [ i ] := y דורשת שתי שורות


3 address code2

op ידי תרגום מונחה דקדוק

arg 1

arg 2

uminus

c

0

*

b

(0)

1

uminus

c

2

*

b

(2)

3

+

(1)

(3)

4

assign

a

(4)

5

ייצוג שלישי של 3-address code

  • indirect triples – השלשות מופרדות מהסדר ביניהן

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

  • (לא פותר את הפעולה הכפולה עבור פעולות טרנריות.)

רשימת פקודות לפי סדר הביצוע הרצוי שלהן

Execution

Order

10

11

0

1

15

12


Types
Types ידי תרגום מונחה דקדוק והקצאות זיכרון למשתנים

  • ניתוח ה-types חשוב מאד לבדיקת שגיאות,

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

...

משתנים קודמים ל-employee

Offset for variable employee

רשומת הפעלה למתודה

employee

מקום למשתנה employee

...


הכרזות והקצאת זכרון ידי תרגום מונחה דקדוק

  • דוגמא:תרגום מונחה דקדוק עם פעולות סמנטיות לחישוב ה- offset.

  • נשמור משתנה גלובלי offset עם גודל השטח שהוקצה עד עתה.

  • לכל משתנה בפרוצדורה – נכניס לטבלת הסמלים ונקבע לו offset.


enter(money, real, 4) offset = offset + 4 ידי תרגום מונחה דקדוק

הכרזות

enter(count, int, 0) offset = offset + 4

P

D4

D1

D5

D2

id

T1

id

T2

T3

id

int

count

real

money

]

balances

num

[

T4

T1.type = int

T1.width = 4

T2.type = real

T2.width = 4

int

98

id.name = count

id.name = money


הכרזות והקצאת זיכרון ידי תרגום מונחה דקדוק

  • האיפוס של offset בהתחלה עובד מצוין לניתוח top-down שבו נפעיל את P → Dבתור הכלל הראשון. אך מה עושים עם ניתוח bottom-up?

  • טריק סטנדרטי:נוסיף marker וכלל שתמיד נראה ראשון, גם ב-LR parsing


הכרזות והקצאת זיכרון ידי תרגום מונחה דקדוק

  • השיטה עובדת מצוין לניתוח top-down שבו נפעיל את P → Dבתור הכלל הראשון ונאפס את offset כנדרש. אך מה עושים עם ניתוח bottom-up?

  • טריק סטנדרטי:נוסיף marker וכלל שתמיד נראה ראשון, גם ב-LR parsing

_____________

P

M

D

Є


לסיכום – ייצוג של קוד ביניים ידי תרגום מונחה דקדוק

  • קוד ביניים סטנדרטי הוא חשוב, ניתן להפריד בין ה-front-end שתלוי בשפת המקור, לבין ה-back-end שתלוי במכונת היעד, ולשלב כל front-end עם כל back-end.

  • השלבים הקודמים בונים עץ מעוטר (עם attributes)

  • נתרגם אותו אל three-address-code שהיא שפת ביניים סטנדרטית.

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

    • אוספים את הקוד לתוויות של משתני הדקדוק.

  • Three-address-code ניתן לייצוג ע"י רביעיות או שלשות (ישירות או עקיפות).

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


יצירת קוד ביניים ידי תרגום מונחה דקדוק


יצירת קוד ידי תרגום מונחה דקדוק

  • אפשרות א' –צבירת קוד ב-attributes של משתנים בעץ הגזירה (למשל, בתכונות מסוג code). כך עשינו עד עתה.

  • אפשרות ב' –יצירת קובץ המכיל את הקוד תוך כדי תהליך הקומפילציה

    • אפשרות זו מעשית (לגזירת bottom-up) אם לכל חוק דקדוק תכונת ה- code של אגף שמאל של החוק מתקבלת משרשור תכונות ה- code של המשתנים באגף ימין של החוק על פי סדר הופעתן (אולי בצירוף מחרוזות נוספות)

    • חסרון:לא מאפשר מניפולציות על הקוד.

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


ביטויים ומשפטי השמה ידי תרגום מונחה דקדוק

  • דקדוק המסגרת:התוכנית מכילה הגדרות של משתנים (כמו קודם) ופרוצדורות.

  • ביטויים ומשפטי השמה:

  • Lookup מחזיר את הכתובת של המשתנה בזיכרון.

  • Emit פולט שורת קוד מתאימה בפורמט three-address-code לתוך הקובץ.

  • הטיפול כאן (ובד"כ בהמשך)הוא לפי bottom-up parsing ולכן מקצים למשתנה מקום בפעם הראשונה שפוגשים אותו = כמשתנה השמאלי בכלל הדקדוק.


ביטויים ומשפטי השמה ידי תרגום מונחה דקדוק

  • דקדוק המסגרת:התוכנית מכילה הגדרות של משתנים (כמו קודם) ופרוצדורות.

  • ביטויים ומשפטי השמה:

  • ניתן לייעל במקום הדרוש למשתנים זמניים: כשיוצאים מתת-עץ אין יותר שימוש במשתנים הפנימיים שלו. ניתן לנהל את המשתנים במחסנית.


ביטויים בוליאניים ידי תרגום מונחה דקדוק

נייצג את false כ-0 ואת true כ-1.

  • חשוב לשים לב – כתובת המטרה ניתנת לחישוב תוך כדי יצירת הקוד


חישוב ביטויים בוליאניים ע"י קפיצה

נייצג את false כ-0 ואת true כ-1.

  • למה זה מועיל?לחישוב מקוצר... אבל נראה קודם דוגמא.


E קפיצה

E

or

E

a

<

b

E

and

E

c

<

d

e

<

f

ביטויים בוליאניים בייצוג מספרי – דוגמא


E קפיצה

E

or

E

a

<

b

E

and

E

c

<

d

e

<

f

ביטויים בוליאניים בייצוג מספרי – דוגמא


E קפיצה

E

or

E

a

<

b

E

and

E

c

<

d

e

<

f

ביטויים בוליאניים בייצוג מספרי – דוגמא


E קפיצה

E

or

E

a

<

b

E

and

E

c

<

d

e

<

f

ביטויים בוליאניים בייצוג מספרי – דוגמא


E קפיצה

E

or

E

a

<

b

E

and

E

c

<

d

e

<

f

ביטויים בוליאניים בייצוג מספרי – דוגמא


E קפיצה

E

or

E

a

<

b

E

and

E

c

<

d

e

<

f

ביטויים בוליאניים בייצוג מספרי – דוגמא


ביטויים בוליאניים – חישוב מקוצר קפיצה

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

  • למשל, בביטוי E1or E2, אם E1 הוא true הרי שלא חשוב לנו מה ערכו של E2.

  • חישוב כזה נקרא lazy evaluation או short circuit boolean evaluation.


100: קפיצהif a < b goto 103

101: T1 := 0

102: goto 104

103: T1 := 1

104: if c < d goto 107

105: T2 := 0

106: goto 108

107: T2 := 1

108: if e < f goto 111

109: T3 := 0

110: goto 112

111: T3 := 1

112: T4 := T2 andT3

113: T5 := T1 andT4

100: if a < b goto 105

101: if !(c < d) goto 103

102: if e < f goto 105

103: T := 0

104: goto 106

105: T := 1

106:

דוגמא:

a < b or (c < d and e < f) ניזכר בביטוי של קודם:

חישוב מקוצר:


תכונות של חישוב מקוצר קפיצה

  • האם החישוב מקוצר שקול לחישוב רגיל?

  • מתי אסור להשתמש בחישוב מקוצר?

  • מתי חייבים להשתמש בחישוב מקוצר?

תשובות:

לא – יתכנו side-effects לחישוב ביטוי בוליאני. דוגמא קלאסית: if ( (i > 0) and (i++ < 10) ) A[i]=i else B[i]=i;

כאשר הגדרת השפה לא מרשה זאת.

כאשר הגדרת השפה מחייבת קיצור, והמתכנת עלול להתבסס על כך.דוגמא קלאסית: if ( (file=open(“c:\grades”) or (die) ) printfile(file);


If else while
טיפול בהפניות בקרה: קפיצהif, else, while.

  • נחזור לאגור את הקוד בתכונה (attribute) בשם קוד. ההבדל בין emit ל- gen: genמחזירה את הפקודה שנוצרה; emit מדפיסה אותה ל- buffer.

  • נתבונן בקפיצות מותנות:

  • אפשרות אחת היא לעבוד כמו קודם, לייצר קוד ל-B לייצר קוד ל-S, ואז לייצר קפיצה לתחילת S או סוף S כתלות בערך של B.

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


If else while1
טיפול בהפניות בקרה: קפיצהif, else, while.

  • מסתבר שיש כאן בעיה עם ההחלטה לאן לקפוץ בזמן הניתוח...

  • כאשר מנתחים את העץ שנפרש מ-B עבור "if B then S” לא יודעים למה S יתפתח ואיפה מתחיל ונגמר הקוד של S, אבל צריך לייצר קפיצות למקומות אלו.

  • השיטה – לכל ביטוי B נצמיד שתי תוויות: B.true, ו-B.false שהן התוויות אליהן החישוב צריך לעבור אם B הוא true (או false בהתאמה).

  • לכל פסוק S נחזיק תווית next שאומרת מה הכתובת של הקוד שאחריו.

  • משוואה סמנטיות מתאימה:B.false = S.next

  • לגבי B.true, נייצר label בין הקוד של B לקוד של S ונייחס לו את B.true.

S

if

B

then

S


התכונה קפיצהnext

  • בגזירה של פסוק S, נייצר את הקוד עם התווית שאחריו:

  • התכונה S.next היא נורשת: הילד מקבל אותה כשהוא נגזר מאביו.

  • תכונת ה-code היא נוצרת: האבא מקבל אותה בעת גזירת ילדיו.

  • ה-labelS.next היא סימבולית. הכתובת המתאימה לה תיוודע רק אחרי שנגזור את כל הביטוי של S.


If b then s

קפיצה to B.true

קוד לחישוב B עם קפיצות החוצה

→ to B.false

B.true:

קוד לחישוב S

B.false:

. . .

If B then S

  • B.false ו- S1.next הן תכונות נורשות

  • S.code היא תכונה נוצרת


If b then s 1 else s 2
If B then S קפיצה1 else S2

→to B.true

→to B.false

B.True ו-B.false לא נקבעים ע"י ההורים ולא ע"י הילדים. אבל הם נקבעים בזמן גזירה שבה B הוא ילד ולכן נחשבים נורשים.

נורש

נוצר


חישוב ביטויים בוליאניים על ידי הפנית בקרה

  • נייצר קוד שקופץ ל-B.true אם הערך של Btrue ול-B.false אם הוא false.

  • איזו צורת חישוב מוצגת כאן? מקוצרת או מלאה?


חישוב ביטויים בוליאניים על ידי הפנית בקרה

  • נייצר קוד שקופץ ל-B.true אם הערך של Btrueול-B.false אם הוא false.

  • נתבונן לדוגמא ב-labelB1.false.

  • הכתובת של ה-label ניתנת לחישוב רק אחרי שנדע את כל הקוד של B1 וכל הקוד שלפני B1.

  • למעשה, אנו נייצר את כל הקוד עם labels סימבוליים, ואחרי כן נבצע מעבר נוסף על העץ כדי לקבוע כתובת לכל label סימבולי, ולעדכן את כתובות הקפיצה בפקודות המתאימות.


Backpatching
Backpatching הפנית בקרה – תיקון לאחור

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

    • השיטה:נשמור לכל label את אוסף הכתובות של פקודות שמדלגות אליו.

    • ברגע שנדע את הכתובת של ה-label, נלך על רשימת הכתובות ונכניס בפקודות הקפיצה המתאימות את הכתובת האמיתית של ה-label.

    • יתרון:מעבר DFS יחיד יספיק (חישבו על אלפי שורות קוד).

    • חסרון:נצטרך להקצות מקום לרשימות של הכתובות.

  • נדגיש שפתרונות שהזכרנו בעבר לא יעבדו.

    • הגזירה אינה S-attributed (יש גם תכונות נורשות, למשל next).

    • היא לא L-attributed (התכונות הנורשות אינן בהכרח נורשות-משמאל)

    • לכן לא נוכל לחשב את התכונות תוך כדי הניתוח.


דוגמא להבהרת הקושי הפנית בקרה

S

B

then

else

if

S1

S2

  • חישבו על פסוק if-then-else.

  • על-מנת לחשב את S1.next צריך כבר לדעת את הקוד של כל הבלוקים B, S1, ו-S2 (כדי לדעת מהי הכתובת שאחריהם).

  • מצד שני, כדי לחשב את הקוד של S1 צריך להעביר לו את S1.next, או S.next, אבל ערך זה לא ידוע לפני החישוב של S1.

  • כאמור, לא נוכל לחשב את הקוד של S1 עם כל כתובות הקפיצה, אבל נוכל לחשב אותו עד כדי "השארת מקום" להכנסה מאוחרת יותר של S1.next.

  • בשיטת ה-backpatching נבנה את הקוד ונשאיר לעצמנו רשימה עבור ה-label הסימבולי S1.next של כל שורות הקוד שבהן יש קפיצה אליו.

  • כשנדע את ערכו של S1.next, נעבור על הרשימה ונעדכן.


פונקציות ליצירה וטיפול בהתחייבויות

  • makelist ( addr ) – יצירת רשימת התחייבויות חדשה המכילה את הכתובת addr. התוצאה – מצביע לרשימה של כתובות של פקודות.

    • addr הוא מספר שורה ברשימת הרביעיות שלנו

    • המשמעות:יש לתקן את הפקודה שבשורה addr כשיתקבל מידע רלוונטי

  • merge ( p1, p2 ) – איחוד הרשימות אליהם מצביעים p1ו- p2. מחזיר מצביע לאיחוד הרשימות.

    • כלומר, שתי הרשימות מכילות פקודות שצריכות לקפוץ לאותו מקום.

  • backpatch ( p, addr ) – קביעת הכתובת addr ככתובת הקפיצה בכל אחת מהפקודות (רביעיות) שברשימה אליה מצביע p


אגירת הקוד בהתחייבויות

  • נניח (כהרגלנו)ניתוח bottom-up כך שהקוד נוצר בסדר הנכון (שמאל לימין, מלמטה למעלה).

  • הניתוח הסמנטי יתבצע במהלך הניתוח התחבירי והקוד ייפלט לתוך buffer עם פקודת emit (פשוט כדי שיהיה נוח לחשוב על כתובות של פקודות).

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

  • כזכור, לכל ביטוי B הצמדנו שתי תוויות: B.true, ו-B.false שהן התוויות אליהן החישוב צריך לעבור אם B הוא true (או false בהתאמה).

  • עתה תהיינה לנו גם זוג רשימות : B.truelist, ו-B.falselist שאומרות באילו פקודות צריך לחזור ולעדכן את הכתובות של : B.true, ו-B.false כשמגלים את ערכיהם.

  • בנוסף, לכל פסוק S שעבורו החזקנו label סימבולי S.next, נחזיק עתה גם רשימה S.nextlist.


אגירת הקוד - המשך בהתחייבויות

  • B.truelist, ו-B.falselist הן תכונות נוצרות: הצאצאים מספרים לאב איפה יש קוד שצריך לתקן.

  • כאשר עולים לאב של B עצמו, נדע מה הכתובת הרלוונטית ונוכל לבצע backpatch ולהכניס אותה לכל הפקודות שנרשמו ברשימה.

  • באופן דומה, ל-S.nextlist תכונות דומות.

  • נשתמש בפונקציה nextinstr שתחזיר את הכתובת של הפקודה הבאה.


חישוב ביטויים בוליאניים על ידי הפנית בקרה

  • כזכור, הקוד שקופץ ל-B.true או ל-B.false לפי הערך של B.

  • קודם היה:

  • ועכשיו עם backpatching:

  • איזו צורת חישוב מוצגת כאן? מקוצרת או מלאה?


חישוב ביטויים בוליאניים על ידי הפנית בקרה

  • כזכור, הקוד שקופץ ל-B.true או ל-B.false לפי הערך של B.

  • קודם היה:

  • ועכשיו עם backpatching:

  • איזו צורת חישוב מוצגת כאן? מקוצרת או מלאה?


חישוב ביטויים בוליאניים על ידי הפנית בקרה

  • כזכור, הקוד שקופץ ל-B.true או ל-B.false לפי הערך של B.

  • קודם היה:

  • ועכשיו עם backpatching:

  • איזו צורת חישוב מוצגת כאן? מקוצרת או מלאה?


Marker
טריק ה- הפנית בקרהmarker הסטנדרטי

  • למשל: B → B1or M B2 ו- M →.

  • בזמן הגזירה של M משיגים את הכתובת של תחילת B1.

B

or

B1

M

B1


B.t = {100, 104} הפנית בקרה

B.f = {103, 105}

B.t = {100}

B.f = {101}

or

M.i = 102

B.t = {104}

B.f = {103, 105}

a

<

b

and

M.i = 104

B.t = {102}

B.f = {103}

B.t = {104}

B.f = {105}

c

<

d

e

<

f

תיקון לאחור


B.t = {100, 104} הפנית בקרה

B.f = {103, 105}

B.t = {100}

B.f = {101}

or

M.i = 102

B.t = {104}

B.f = {103, 105}

a

<

b

and

M.i = 104

B.t = {102}

B.f = {103}

B.t = {104}

B.f = {105}

c

<

d

e

<

f

תיקון לאחור


B.t = {100, 104} הפנית בקרה

B.f = {103, 105}

B.t = {100}

B.f = {101}

or

M.i = 102

B.t = {104}

B.f = {103, 105}

a

<

b

and

M.i = 104

B.t = {102}

B.f = {103}

B.t = {104}

B.f = {105}

c

<

d

e

<

f

תיקון לאחור


B.t = {100, 104} הפנית בקרה

B.f = {103, 105}

B.t = {100}

B.f = {101}

or

M.i = 102

B.t = {104}

B.f = {103, 105}

a

<

b

and

M.i = 104

B.t = {102}

B.f = {103}

B.t = {104}

B.f = {105}

c

<

d

e

<

f

תיקון לאחור


B.t = {100, 104} הפנית בקרה

B.f = {103, 105}

B.t = {100}

B.f = {101}

or

M.i = 102

B.t = {104}

B.f = {103, 105}

a

<

b

and

M.i = 104

B.t = {102}

B.f = {103}

B.t = {104}

B.f = {105}

c

<

d

e

<

f

תיקון לאחור


B.t = {100, 104} הפנית בקרה

B.f = {103, 105}

B.t = {100}

B.f = {101}

or

M.i = 102

B.t = {104}

B.f = {103, 105}

a

<

b

and

M.i = 104

B.t = {102}

B.f = {103}

B.t = {104}

B.f = {105}

c

<

d

e

<

f

תיקון לאחור




לסיכום הפנית בקרה

  • יצירת קוד משולבת בניתוח הסמנטי (בפעולות הסמנטיות)

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

  • הניתוח של ביטויים לוגיים ופסוקי הפניית הבקרה הם יותר מסובכים.

  • ראשית צריך להחליט על ביצוע מקוצר (או לא).

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

  • אפשרות אחת:שימוש ב-labels סימבוליים ומעבר נוסף לעידכונם לכתובת אמיתית.

  • אפשרות שניה - backpatching:מעבר יחיד על העץ, אך שמירת רשימה של כל המקומות אליהן צריך להכניס את הכתובת של label מסוים. כשמגלים את מיקום ה-label, מעדכנים את כל הפקודות לפי הכתובות שברשימה.


ad