מבחן סוף סמסטר מועד ג' תאריך: 27.05.2008 מרצה אחראית: מתרגלים: דר' שירלי הלוי-גינסברג אלכס קוגן גלעד קותיאל הוראות: בטופס המבחן 5 עמודים ו- 4 דפי נוסחאות. בדקו שכל העמודים ברשותכם. א. משך המבחן שלוש שעות (180 דקות). ב. אסור כל חומר עזר פרט לדף הנוסחאות המצורף לבחינה. ג. 5 שאלות. כל השאלות הינן חובה. משקל כל שאלה מופיע בראשיתה. (חלוקת במבחן ד. המשקל בין הסעיפים בכל שאלה אינה בהכרח אחידה.) ניתן לציין לגבי סעיף או שאלה "לא יודע/ת". תשובה זו תזכה ב- 10% מהניקוד של הסעיף ה. או השאלה. תשובות שגויות לא יזכו בניקוד. קראו את כל המבחן לפני שאתם מתחילים לענות על השאלות. ו. את התשובות לשאלות יש לרשום במחברת הבחינה בלבד. ז. בהצלחה! שאלה (10 1 נק') \n { printf("1"); } { printf("2"); } [a-c]+ { printf("3"); } [A-C]+ { printf("4"); } [1-3]+ { printf("5"); } [acb13]+ { printf("6"); } [^a-c]+[^a-c]+[^1-9]+ { printf("7"); } בהינתן חוקי Lex הבאים: מה יהיה הפלט של המנתח הלקסיקלי הנוצר, על כל אחת משורות קלט הבאות (הניחו כי כל שורה מופיעה בקובץ קלט נפרד ומסתיימת בסימן סוף שורה "n\"): abcabc123 321CBAcba BaB1cAb AAAAacac1231 א. ב. ג. ד. 1
שאלה (15 2 נק') מסמך XML ייקרא בנוי היטב אם: 1. למסמך יש אלמנט שורש יחיד. 2. האלמנטים מקוננים היטב. <person> <name> Yosi </name> <age> 25 </age> </person> <person> <name> Yosi <age> 25 </name> </age> </person> דוגמה למסמך בנוי היטב: דוגמה למסמך שלא בנוי היטב: כתבו קובץ הגדרות עבור Bison שיצור מנתח תחבירי המקבל מסמך XML ובודק האם הוא בנויי היטב. על המנתח לתת פלט בהתאם. הניחו כי המנתח הלקסיקלי מחזיר את האסימונים הבאים: START_TAG עבור תג פותח END_TAG עבור תג סוגר ELEM עבור אלמנט שאינו תג פותח או סוגר בנוסף, הניחו כי לשני סוגי אסימונים ראשונים קיים שדה type מסוג string שמכיל את שם התג. %{ %} %% %% <C++ declarations> <definition section> <rule section> <C++ code section> לשימושכם, שלד של קובץ הגדרות עבור :Bison 2
שאלה (15 3 נק') יהיו S 1, S 2 שני דקדוקים המוגדרים מעל אותו אוסף של משתנים וטרמינלים ובעלי אותו סימן התחלתי. נגדיר פעולת חיתוך על S 1 ו- S, 1 S 2 S, 2 כדקדוק עם אוסף כללי גזירה שמופיעים בכל אחד משני הדקדוקים S 1 ו- S. 2 באופן דומה, נגדיר פעולת איחוד של שני הדקדוקים, S, 1 S 2 כדקדוק עם אוסף כללי גזירה שמופיעים בלפחות אחד משני הדקדוקים S 1 ו- S. 2 הוכח או הפרך את הטענות הבאות: א. הם דקדוקי,LR(0) אזי.LR(0) הוא דקדוק S 1 S 2 ב. אם S 1 ו- S 2 אם S 1 ו- S 2 הם דקדוקי,LR(0) אזי.LR(0) הוא דקדוק S 1 S 2 יהיו,S S 1 S, 2,, S k דקדוקים המוגדרים מעל אותו אוסף של משתנים וטרמינלים ויהי 'S דקדוק המתקבל מ- S ע "י החלפת כל סימן טרמינלי בדקדוק בסימן ההתחלה של אחד הדקדוקים,S 1, S 2, S k בתוספת כל הכללים של הדקדוקים S 1, S 2,, S k (פעולה זו נקראת הצבה חסרת הקשר). S' E 3 E 1 E 2 E 1 a E 2 b S E 3 c d S 1 E 1 a S 2 E 2 b לדוגמה: הוכח או הפרך את הטענה הבאה: אם ג. S, S 1,S 2,, S k הם דקדוקי,LR(0) אזי S' הוא דקדוק.LR(0) שאלה (35 4 נק') בשאלה זו נדון בתרגום מבנה בקרה switch בשיטת.backpatching S switch ( E ) { CL } CL CL C C C case num : S ; break ; להזכירכם, מבנה בקרה זה נתון ע"י דקדוק הבא: ראינו בכיתה סכימת תרגום המבוססת על "סולם של פקודות."if עתה נראה כי, תחת תנאים מסוימים, ניתן לתרגם מבנה זה לשפת ביניים בצורה יעילה יותר. א. נניח כי ידוע שטווח ערכים אותם מקבל טרמינל num בכל אחד מה- case -ים הוא רציף ומתחיל מ- 0. לדוגמה: switch (x + y) { case 0: print("0"); break; case 1: print("1"); break; case 100: print("100"); break; } 3
הציעו פריסת קוד, מתאימה לשיטת,backpatching במספר קבוע של פקודות if בשפת הביניים. המנצלת עובדה זו ומשתמשת הנחות:.i ניתן להניח כי, בנוסף לפקודות בשפת ביניים שלמדנו, קיימת פקודה "t,"goto כאשר t הוא משתנה משמעות הפקודה היא קפיצה לכתובת אשר מצויה בתוך משתנה t..ii כמו כן, ניתן להניח כי גודל כל פקודה בשפת ביניים הוא 1. ב. כתבו סכימת תרגום בשיטת backpatching המייצרת את פריסת הקוד שהצעתם בסעיף הקודם. על הסכימה להיות יעילה ככל האפשר, הן מבחינת זמן הריצה שלה והן מבחינת המקום בזיכרון שנדרש עבור התכונות הסמנטיות. שימו לב: אין להשתמש בכללים סמנטיים באמצע כלל גזירה. אין להשתמש במשתנים גלובליים בזמן קומפילציה. המשתנים S ו- E הם המשתנים הסטנדרטיים המופיעים בדף הנוסחאות, ויש להם כללי גזירה בנוסף לכלל המופיע בשאלה. למשתנים C ו- CL אין כללי גזירה פרט לכללים המוצגים בשאלה. ג. עתה ננסה להגמיש את ההנחה כי טווח ערכים אותם מקבל טרמינל num בכל אחד מה- case -ים הוא רציף ומתחיל מ- 0. לדוגמה, במבנה הבא switch (x + y) { case 2: print("2"); break; case 3: print("3"); break; case 5: print("5"); break; case 8: print("8"); break; case 9: print("9"); break; } הטווח הוא לא רציף, מכיל מרווחים קטנים ומתחיל מ- 2. if כיצד ניתן לטפל במבני switch שהצעתם בסעיף א'? כאלה תוך שימוש באותו מספר של פקודות כמו שימו לב: אין צורך לצייר סכימת פריסת קוד, אך יש להסביר את הרעיון בפירוט. ד. באופן כללי, בהינתן מבנה,switch מתי כדאי להשתמש בסכימה שהצעתם בסעיף א' ומתי בסכימה של "סולם של פקודות "if שראינו בכיתה? ה. אילו בעיות עשויות להתעורר בשלבים הבאים של תהליך הקומפילציה עקב בפקודה "t "goto שהוצגה בסעיף א'? כיצד ניתן לפתור אותן? שימוש 4
שאלה (25 5 נק') נניח כי בנוסף לפקודות שלמדנו, שפת ביניים מכילה גם פקודת קלט read x הקולטת את ערכו של משתנה x מהמשתמש. נאמר שמשתנה x בנקודה p בתכנית הוא קלט חיצוני אם קיים מסלול בתכנית המגיע לנקודה p שבו הערך של x בנקודה p נקרא כקלט מבחוץ (ע"י פקודת.(read x נאמר שמשתנה x בנקודה p נתון להשפעה חיצונית אם ערכו של x בנקודה p מושפע ממשתנה y שהוא קלט חיצוני. כלומר, לצורך חישוב ערכו של x בנקודה p משתמשים בערכו של משתנה y שהוא קלט חיצוני, והחישוב יכול להתבצע במספר שלבים. read x y = 2*x y = y + 5 z = 3*y w = 2*z לדוגמה: בבלוק הבסיסי הבא בנקודה אחרי הפקודה האחרונה x הוא קלט חיצוני ו- w נתון להשפעה חיצונית. א. ב. הציעו אלגוריתם מבוסס- DFA המקבל כקלט CFG שבו כל צומת הוא בלוק בסיסי, ומחשב את קבוצת המשתנים שהם קלט חיצוני בכניסה וביציאה לכל בלוק. הציעו אלגוריתם מבוסס- DFA המקבל כקלט CFG שבו כל צומת הוא בלוק בסיסי, ומחשב את קבוצת המשתנים הנתונים להשפעה חיצונית בכניסה וביציאה לכל בלוק. בהצלחה!! 5
נוסחאות ואלגוריתמים כל ההגדרות מתייחסות לדקדוק S).G = (V, T, P, first(α) = { t T α * tβ β (V T)* } Top Down follow(a) = { t T {$} S$ * αatβ α (V T)* β (V T)*(ε $) } select(a α) = first(α) follow(a) first(α) α * ε otherwise הגדרה: דקדוק G הוא LL(1) אם ורק אם לכל שני כללים ב- G השייכים לאותו משתנה A מתקיים: select(a α) select(a β) = הגדרת טבלת המעברים P {error} M : V (T {$}) עבור דקדוק :LL(1) M[A, t] = A α t select(a α) error t select(a α) for all A α P Q.push(S) while!q.empty() do X = Q.pop() t = next token if X T then if X = t then SHIFT else ERROR else end if end while t = next token if t = $ then ACCEPT else ERROR // X V if M[X, t] = error then ERROR else REPLACE(X, t) אלגוריתם מנתח :LL(1) 6
(B γ) closure(i) גם,B γ P Bottom Up פריט LR(0) הוא α β) (A כאשר A αβ P סגור (closure) על קבוצת פריטים I מוגדר באופן אינדוקטיבי:.closure(I) = I בסיס: o o צעד: אם closure(i),(a α Bβ) אז לכל פונקציית המעברים של האוטומט: δ(i, X) = { closure(a αx β) (A α Xβ) I } פריט LR(1) הוא t) (A α β, כאשר t T {$},A αβ P סגור (closure) על קבוצת פריטים I מוגדר באופן אינדוקטיבי:.closure(I) = I בסיס: o o צעד: אם closure(i),(a α Bβ, t) אז לכל B γ P ולכל first(βt),x גם (B γ, x) closure(i) פונקציית המעברים של האוטומט: δ(i, X) = { closure(a αx β, t) (A α Xβ, t) I } הגדרת טבלת action למנתח :SLR SHIFT j δ(i i, t) = I j action[i, t] = REDUCE k rule k is A α, (A α ) I i and t follow(a) ACCEPT (S S ) I i and t = $ ERROR otherwise הגדרת טבלת action למנתח :LR(1) SHIFT j δ(i i, t) = I j action[i, t] = REDUCE k rule k is A α and (A α, t) I i ACCEPT (S S, $) I i and t = $ ERROR otherwise הגדרת טבלת goto למנתח SLR ו- :LR(1) goto[i, X] = j error δ(i i, X) = I j otherwise 7
אלגוריתם מנתח :shift/reduce Q.push(0) // where 0 is the initial state of the prefix automaton while true do k = Q.top().state t = next token do action[k, t] end while ניתוח סמנטי אלגוריתם dfvisit לניתוח סמנטי עבור הגדרות :L-attributed procedure dfvisit(node n) : foreach child m of n in left-to-right order do evaluate the inherited attributes of m dfvisit(m) end evaluate the synthesized attributes of n ייצור קוד בשיטת Backpatching יוצרת רשימה ריקה עם איבר אחד (ה"חור".(quad מחזירה רשימה ממוזגת של הרשימות list1, list2 מדפיסה קוד בשפת הביניים ומאפשרת להדפיס פקודות קפיצה עם "חורים". מחזירה את כתובת הרביעיה (הפקודה) הבאה שתצא לפלט. מקבלת רשימת "חורים" list וכתובת,quad ו"מטליאה" את הרשימה כך שבכל החורים תופיע הכתובת.quad מחזירה שם של משתנה זמני חדש שאינו נמצא בשימוש בתכנית. פונקציות: makelist(quad) merge(list1,list2) emit(code string) nextquad() backpatch(list, quad) newtemp() משתנים סטנדרטיים: S: גוזר פקודות (statements) בשפה. תכונות: :nextlist o רשימת כתובות של פקודות המכילות חור שיש להטליא בכתובת הפקודה הבאה לביצוע אחרי הפקודה הנגזרת מ- S. B: גוזר ביטויים בוליאניים. תכונות: :truelist o רשימת כתובות של פקודות המכילות חור שיש להטליא בכתובת אליה יש לקפוץ אם הביטוי הבוליאני מתקיים. :falselist o רשימת כתובות של פקודות המכילות חור שיש להטליא בכתובת אליה יש לקפוץ אם הביטוי הבוליאני אינו מתקיים. E: גוזר ביטויים אריתמטיים. תכונות: :E.place o שם המשתנה הזמני לתוכו מחושב הביטוי האריתמטי. 8
קוד ביניים x := y op z x := op y x := y goto L if x relop y goto L param x call p, n return y x := y [ i ] x [ i ] := y x := addr y x := * y * x := y סוגי פקודות בשפת הביניים: 1. משפטי השמה עם פעולה בינארית 2. משפטי השמה עם פעולה אונרית 3. משפטי העתקה 4. קפיצה בלתי מותנה 5. קפיצה מותנה 6. פרמטרים וקריאה לפרוצדורות indexed assignments.7 8. השמה של כתובות ומצביעים.G = (V, E) Data-Flow Analysis ההגדרות מתייחסות ל CFG : in(b) = Ι (S,B) E out(b) = f B out(s) ( in(b) ) הצורה הכללית של המשוואות בחישוב סריקה קדמית: = in(b) או Υ (S,B) E out(s) out(b) = in(b) = f Ι (B,S) E B in(s) הצורה הכללית של המשוואות בחישוב סריקה אחורית: או ( out(b) ) out(b) = Υ (B,S) E in(s) 9