ניתוח תחבירי ( Parsing ) - המשך

Preview:

DESCRIPTION

ניתוח תחבירי ( Parsing ) - המשך. Wilhelm, and Maurer – Chapter 8 Aho, Sethi, and Ullman – Chapter 4. תזכורת: סוגי הניתוח התחבירי. top-down – מהשורש לעלים (נקרא גם – "ניתוח תחזית" – predictive ) - PowerPoint PPT Presentation

Citation preview

( - המשךParsingניתוח תחבירי )

Wilhelm, and Maurer – Chapter 8Aho, Sethi, and Ullman – Chapter 4

התחבירי: הניתוח סוגי תזכורת

top-down – "מהשורש לעלים )נקרא גם – "ניתוח תחזית – predictive)

bottom-up מהעלים לשורש – מעבירים למחסנית, או מחליפים צד – (shift reduce)ימין בסימן מהצד השמאלי של חוק הדקדוק

x y

s

x y

s

מתרגם דקדוק לקוד באופן Recursive Descentאלגוריתם הבא:

עבור כלnonterminal.מגדירים פונקציה המנתח מתחיל לפעול מהפונקציה המתאימה

הראשון.nonterminalל-:כל פונקציה מחקה את החוק שעבורו הוגדרה, באופן הבא

terminal מתורגם לקריאת הלקסמה המתאימה מהקלט.

nonterminal מתורגם להפעלת הפונקציה המתאימה לו.

אם ישנם כמה חוקי גזירה עבור אותוnonterminal ,.lookaheadבוחרים ביניהם בעזרת

Recursive Descentתזכורת:

תזכורת: כתיבת פונקציות בהתאם לדקדוק

E → LIT | ( E OP E ) | not ELIT → true | falseOP → and | or | xor

void E() {if (lookahead {TRUE, FALSE}) LIT();else if (lookahead = LPAREN) match(LPARENT);

E(); OP(); E();match(RPAREN);

else if (lookahead = NOT) match(NOT); E();else error;

}

void LIT() {if (lookahead = TRUE) match(TRUE);else if (lookahead = FALSE) match(FALSE);else error;

}

void OP() {if (lookahead = AND) match(AND);else if (lookahead = OR) match(OR);else if (lookahead = XOR) match(XOR);else error;

}

בעיות: תזכורת

, או כללים המתחילים εאיך מתגברים על כללי-?εב-

, זו הופכת להיות ברירת FIRST ב-εאם יש המחדל.

מה קורה עם רקורסיה שמאלית?E → E A E | ( E ) | – E | idA → + | – | * | / | ^

מחליפים את הדקדוק. לכל דקדוק עם רקורסיה שמאלית מיידית יש

דקדוק שקול נטול רקורסיה שמאלית.

? לנו עוזר זה איך

פונקציה – עם קוד לנו יש יופי. גזירה כלל לכל מתאימה

הקלט לגזירת בהתאם מופעל הקוד. הנתון מהדקדוק

, אבל , למשל לקבל לנו עוזר זה איךגזירה ?עץ

הגזירה במהלך פעולות הוספת

בכל פעם שנקראת אחת הפונקציות בדוגמא ()OP ו-()E(), LIT(למשל,

שלנו), פירוש הדבר ש"איתרנו" צעד בגזירה.

בכל צעד כזה ניתן לבצע פעולות שונות!בפרט, ניתן די בקלות לבנות עץ בעזרת

הפעולות הללו.

הגזירה במהלך פעולות הוספת

דרך אחת לקבל עץ מהפונקציות הקיימות: כל פונקציה מחזירה רשומה מסוגNode

(צומת בעץ)..כל רשומה כזו מכילה רשימה של בנים בכל קריאה לפונקציה אחרת (או

), מוסיפים את תוצאת הקריאה matchל- שנבנה כעת.Nodeל-

הגזירה במהלך פעולות הוספת

Node E() {result = new Node();if (lookahead {TRUE, FALSE}) // E → LIT

result.addChild(LIT());else if (lookahead = LPAREN) // E → ( E OP E )

result.addChild(match(LPARENT));result.addChild(E()); result.addChild(OP()); result.addChild(E());result.addChild(match(RPAREN));

else if (lookahead = NOT) // E → not E

result.addChild(match(NOT)); result.addChild(E());else error;return result;

}

הגזירה במהלך פעולות הוספת

ואז, למשל:input = “(not true and false)”;Node treeRoot = E();

E

( E OP E )

not LIT

falsetrue

and LIT

הגזירה במהלך פעולות הוספת

כאמור, בפועל בד"כ לא באמת בונים עץ. ייצוג של התוכנית כולה בזכרון יכול

להיות מסובך ו"כבד".אבל באופן שקול, ניתן לבצע כל פעולה

שהיא בפונקציות השונות המתקבלות .RDבאלגוריתם

פעולות אלה תייצרנה, בסופו של דבר, .parserאת הפלט של ה-

RDהתאמת הדקדוק ל-

.RDלא כל דקדוק מתאים ל-.רקורסיה שמאליתהבעיה הקשה:

כזכור, קל לבטל רקורסיה שמאלית ישירה:

?רקורסיה שמאלית עקיפהמה לגבי S → Aa | b A → Ac | Sd | ε

A → Aα | β

A → βA’A’ → αA’ | ε

: אלגוריתם עקיפה שמאלית רקורסיה ביטול

ו/או לולאות.ε אם הדקדוק מכיל כללי עשוי לא לעבוד

Left Factoring בעזרת lookaheadהקטנת הצורך ב-

FIRST היא התנגשויות ב-RDבעיה נוספת של של כללי גזירה שונים לאותו משתנה.

, פירוק שמאלי – Left Factoringהפתרון: אלגוריתם המפיק דקדוק חלופי ללא הבעיה.

למשל:

S → if E then S else S | if E then S | T

S → if E then S S’ | TS’→ else S | ε

Left Factoringאלגוריתם

וזהו?

קיימות טרנספורמציות המייצרות דקדוק ללא FIRSTרקורסיה שמאלית וללא התנגשויות ב-

מדקדוקים רבים.אפשר לגזור כל דקדוק שעבר "טיפול" כזה

.RDבהצלחה בעזרת

מסקנה: אפשר לגזור שפות רבות ושונות .RDבעזרת

לשם מה אנו זקוקים לאלגוריתמים אחרים?

)LL)1 אלגוריתם

)LL)kאלגוריתם

הוא אלגוריתם:LL(k)אלגוריתם top-down,,מבוסס טבלה) סורק את הקלט משמאלL,לימין () מניב את הגזירה השמאליתL,ביותר (-וזקוק לlookahead בגודל k.

המקרה הפשוט ביותר הוא אלגוריתם LL(1).

)LL)kשפות

אם אפשר לגזור אותה LL(k)שפה נקראת .LL(k) parserבעזרת

k עבור LL(k) גוזר שפות RDאלגוריתם בלתי-חסום.

בעזרת LL(k)בדרך-כלל גוזרים שפות אלגוריתמים מבוססי-טבלה. אלגוריתמים אלו

.LL(k) parsersהם הידועים בשם

)LL)1אלגוריתם

מחסנית

Parser

קלט

פלט

מעברים טבלת

המעברים טבלת

משתמשים בטבלה המכתיבה, עבור LL(1)ב-כל מצב נתון, באיזה כלל גזירה להשתמש.

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

תוכן הטבלה: חוקי גזירה.

למשל...

()nottrue

false

andorxor$

E2311

LIT45

OP678

(1) E → LIT(2) E → ( E OP E ) (3) E → not E(4) LIT → true(5) LIT → false(6) OP → and(7) OP → or(8) OP → xor

האלגוריתם

: המשתנה הראשון בדקדוק, ו-$ (סימן לסוף אתחול המחסניתהקלט).

המחסנית יכולה להכיל אסימונים או משתנים. "$" הוא אסימוןמיוחד, לצורך זה.

אם בראש המחסנית יש אסימון: :שגיאהאם האסימון הבא בקלט אינו זהה. אם הוא תואם את הקלט: צרוך את תו הקלט; הסר את האסימון

).סיימנומהמחסנית. (אם האסימון הוא $,

אם בראש המחסנית יש משתנה:.מצא את התא בטבלה המתאים למשתנה זה ולתו שבראש הקלט:שגיאה אם התא ריק.:הסר את המשתנה מראש המחסנית; הוסף למחסנית את אחרת

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

ביותר (הוא ישאר בראש המחסנית).

הטבלה בניית

. בתרגול...

בטבלה- משמעויות ריבוי

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

? דקדוקים אילו? הבעיה על להתגבר ניתן כיצד

)LL)kאלגוריתמים

היא (במקרה LL(k), הטבלה הנדרשת לאלגוריתם k>1עבור .סיבוכיות אקספוננציאליתהגרוע) בעלת

parsersלכן, עד לא מזמן האמינו שלא יהיה מעשי לבנות לשפות תכנות "אמיתיות" בעזרת אלגוריתם זה.

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

ניתן לבנות (ארה"ב) שהמקרה הגרוע הוא למעשה נדיר, וparsers פרקטיים עם LL(k).

הכלי שפיתחו נקרא כיוםANTLR. כלים אחרים המבוססים עלLL(k): JavaCC משמש לבניית)

(גם SableCC עצמו), javac, כולל מהדר Javaמהדרים ב-), ואחרים.Javaהוא ב-