איתן אביאור תורת הקומפילציה 1 תחביר ומשמעות ( )Syntax and Semantics שני חלקים המגדירים שפה : • תחביר ( ─ )syntax הגדרת המלים והמשפטים החוקיים בשפה – רישום באמצעות דקדוק.

Download Report

Transcript איתן אביאור תורת הקומפילציה 1 תחביר ומשמעות ( )Syntax and Semantics שני חלקים המגדירים שפה : • תחביר ( ─ )syntax הגדרת המלים והמשפטים החוקיים בשפה – רישום באמצעות דקדוק.

Slide 1

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 2

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 3

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 4

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 5

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 6

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 7

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 8

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 9

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 10

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 11

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 12

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 13

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 14

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 15

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 16

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 17

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 18

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 19

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 20

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 21

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 22

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 23

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 24

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 25

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 26

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 27

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 28

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 29

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 30

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 31

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 32

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 33

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 34

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 35

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 36

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 37

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 38

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 39

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 40

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 41

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬


Slide 42

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪1‬‬

‫תחביר ומשמעות‬
‫(‪)Syntax and Semantics‬‬
‫שני חלקים המגדירים שפה‪:‬‬
‫• תחביר (‪ ─ )syntax‬הגדרת המלים והמשפטים החוקיים בשפה‬
‫– רישום באמצעות דקדוק חסר הקשר (‪)context free grammar‬‬
‫– ע"פ שיטת ‪)Backus-Naur Form( BNF‬‬
‫• משמעות (‪ ─ )semantics‬הגדרת הפרוש של המלים והמשפטים‬
‫החוקיים‬
‫– הסימונים הקיימים מסובכים‬
‫– שימוש בהגדרות לא פורמליות‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪2‬‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Transtation‬‬
‫שיטה המשלבת את הוראות התרגום לשפת מטרה‬
‫בתוך הדקדוק המגדיר את תחביר שפת המקור‪.‬‬

‫נשתמש בה להלן‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪3‬‬

‫שיטות רישום לביטויים‬
‫אריתמטיים‬
‫‪9–5+2‬‬

‫• רישום פנימי (‪)infix‬‬
‫– הרישום המקובל בד"כ‬
‫‪+–952‬‬
‫• רישום תחיליות (‪)prefix‬‬
‫– הרישום המקובל לפונקציות ו‪/‬או אופרטורים לא‪-‬בינאריים‬
‫‪95–2+‬‬
‫• רישום סופיות (‪)postfix‬‬
‫– רישום נוח לחישוב במכונת מחסנית‬
‫(מחשבוני ‪ ,HP‬שפת ‪)PostScript‬‬
‫רישום תחיליות ורישום סופיות פוטר מהצורך בשימוש בסוגריים‬
‫מפני שהקריאה שלהם הינה חד משמעית‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪4‬‬

‫מבנה המהדר הפשוט‬
‫(צד קדמי)‬
‫ייצוג‬
‫ביניים‬

‫תרגום‬
‫מונחה‬
‫תחביר‬

‫זרם‬
‫התמניות‬

‫מנתח‬
‫לקסיקאלי‬

‫זרם‬
‫התווים‬

‫לצורך פשטות הניתוח הלקסיקאלי‬

‫• שפת המקור‪:‬‬
‫– ביטויים אריתמטיים בשיטה פנימית‬
‫– מספרים בעלי ספרה אחת‬
‫– פעולות חיבור וחיסור בלבד‬
‫• שפת המטרה‬
‫– ביטויים אריתמטיים בשיטת הסופיות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪5‬‬

‫דקדוק חסר הקשר‬
‫(‪)Context Free Grammar‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬

‫‪.4‬‬

‫קבוצת ‪ ─ terminals‬הם התמניות המיוצרות ע"י המנתח‬
‫הלקסיקאלי‬
‫קבוצת ‪ nonterminals‬או בשם אחר משתנים (‪)variables‬‬
‫קבוצה של כללי גזירה (‪ .)productions‬כלל גזירה מורכב מ‪:‬‬
‫משתנה הנקרא צד שמאל (‪)left side‬‬
‫̶‬
‫חץ‬
‫̶‬
‫סדרה של תמניות ומשתנים ─ הנקראת צד ימין (‪)right side‬‬
‫̶‬
‫ציון אחד המשתנים בתור סמל התחלה (‪)start‬‬
‫קונבנציה‪:‬‬

‫איתן אביאור‬

‫המשתנה בצד השמאלי של כלל הגזירה הראשון‬
‫הינו סמל ההתחלה‬
‫תורת הקומפילציה‬

‫‪6‬‬

‫דוגמה ─ דקדוק הביטויים שלנו‬
‫‪list  list + digit │ list – digit │ digit‬‬

‫‪digit  0 │ 1 │ 2 │ 3 │ 4‬‬
‫‪│5│6│7│8│9‬‬

‫‪list  list + digit‬‬
‫‪list  list - digit‬‬
‫‪list  digit‬‬
‫‪digit  0‬‬
‫‪digit  1‬‬
‫‪...‬‬
‫‪digit  9‬‬

‫• כתב נוטה מציין משתנים‬
‫• כתב קבוע מציין תמניות‬
‫• את המחרוזת הריקה מציינים ע"י ‪( ε‬אפסילון)‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪7‬‬

‫דוגמה ─ עץ פריסה (‪)Parse Tree‬‬
‫הביטוי ‪ 9 – 5 + 2‬נפרס ע"י עץ הפריסה הבא‪:‬‬
‫‪list‬‬
‫‪list‬‬

‫‪digit‬‬

‫‪list‬‬

‫‪digit‬‬

‫‪digit‬‬
‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪-‬‬

‫‪9‬‬
‫‪8‬‬

‫דוגמה נוספת לדקדוק‬
block
 { opt_stmts }
opt_stmts  stmt_list │ ε
stmt_list  stmt_list stmt │ stmt

9

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫מטה‪-‬משתנים‬
‫(‪)Meta-Variables‬‬
‫מטה‪-‬משתנה (‪ )meta-variable‬הינו שם המסמן (ע"פ ההקשר)‬
‫• תמנית כלשהי‬
‫• משתנה כלשהו‬
‫• מחרוזת כלשהי (אפילו ריקה) של תמניות ומשתנים‬
‫נסמן מטה‪-‬משתנים באותיות גדולות נוטות ‪Z . . . ,B ,A‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪10‬‬

‫עץ פריסה (‪)Parse Tree‬‬
‫מראה באופן ציורי כיצד נגזרת מחרוזת בשפה ע"י הדקדוק‪:‬‬
‫‪ (1‬השורש הוא סמל התחלה‬
‫‪ (2‬כל עלה הינו תמנית או ‪ε‬‬
‫‪ (3‬כל צומת פנימי מסומן ע"י משתנה‬
‫‪ (4‬אם ‪ A‬הינו משתנה המסמן צומת‬
‫ו‪ X1,X2, … Xn-‬הם שמות הצמתים שתחתיו (משמאל לימין)‬
‫אזי ‪ A  X1X2…Xn‬הינו כלל גזירה‬
‫‪ (5‬במקרה מיוחד יהיה לצומת בן יחיד המסומן ב‪ε-‬‬
‫וזאת כאשר קיים כלל גזירה מהצורה ‪A  ε‬‬
‫תנובה (‪ ─ )yield‬שורת העלים של עץ פריסה שהיא המחרוזת הנוצרת‬
‫(‪ )generated‬או הנגזרת (‪ )derived‬מהמשתנה שבראש העץ‪.‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪11‬‬

‫רב משמעיות (‪)Ambiguity‬‬
‫דקדוק עשוי להיות רב‪-‬משמעי במובן שניתן לגזור ממנו מחרוזת‬
‫מסוימת ביותר מאשר דרך אחד‪.‬‬
‫‪string ‬‬
‫‪string ‬‬
‫‪string ‬‬

‫דוגמה‪:‬‬
‫‪string + string‬‬
‫‪string - string‬‬
‫‪0│1│2│3│4│5│6│7│8│9‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬
‫המשמעות‪:‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬
‫‪string‬‬

‫‪2‬‬

‫‪9-(5+2)=2‬‬
‫תורת הקומפילציה‬

‫‪+‬‬

‫המשמעות‪:‬‬

‫‪5‬‬

‫‪-‬‬

‫‪9‬‬

‫‪(9-5)+2=6‬‬
‫‪12‬‬

‫קדימות והתחברות‬

‫(‪)Precedence and Associativity‬‬
‫כללים הבאים לקבוע מהי המשמעות הנכונה של ביטוי‬
‫(ברישום פנימי) שבלעדיהם הינו רב‪-‬משמעות‪.‬‬
‫קדימות (‪)precedence‬‬
‫•‬

‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים‬

‫התחברות (‪)associativity‬‬
‫•‬

‫מיהו האופרטור אליו מתקשר אופרנד הניצב בביטוי בין שני אופרטורים בעלי אותה‬
‫קדימות‬

‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של אופרטורים בעלי‬
‫אותה קדימות‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪13‬‬

‫קדימות (‪)Precedence‬‬
‫קדימות (‪)precedence‬‬
‫מיהו האופרטור החזק יותר אליו מתקשר אופרנד הניצב בביטוי בין‬
‫שני אופרטורים‬

‫‪c‬‬

‫‪c‬‬

‫‪b‬‬

‫‪d‬‬

‫‪a‬‬

‫‪ab‬‬

‫)‪ a – (b  c‬‬
‫)‪ a  (b  c‬‬

‫‪a – b  c‬‬
‫‪a  b  c‬‬

‫))‪a (b – c/d) a  (b – (c / d‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪14‬‬

‫התחברות (‪)Precedence‬‬
‫התחברות (‪)associativity‬‬
‫• מיהו האופרטור אליו מתקשר אופרנד בביטוי הניצב בין שני‬
‫אופרטורים בעלי אותה קדימות‬
‫או‬
‫• מאיזה כיוון מתחילים את החישוב של תת‪-‬ביטוי המכיל סדרה של‬
‫אופרטורים בעלי אותה קדימות‬
‫התחברות שמאלית (‪)left associativity‬‬
‫‪a – b + c  ( a – b ) + c‬‬
‫התחברות ימנית (‪)right associativity‬‬
‫) ‪a – ( b + c‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪a – b + c ‬‬
‫‪15‬‬

)Expressions( ‫דקדוק לביטוים‬
‫מתוך טבלה המגדירה את כללי הקדימות והתחברות של‬
.‫משמעי לשפה‬-‫אופרטורים בביטוי ניתן לבנות דקדוק חד‬
:‫דוגמה‬
right: **
left: 
/
left: + –
expr
term
factor
base
16






expr + term │ expr – term
term  factor │ term / factor
base  factor │ base
digit │ ( expr )
‫תורת הקומפילציה‬

│ term
│ factor

‫איתן אביאור‬

)Statements( ‫דקדוק לפסוקים‬
stmt

 opt_expr ;







block
if ( expr ) stmt
if ( expr ) stmt else stmt
while ( expr ) stmt
do stmt while ( expr ) ;
for ( opt_expr ; opt_exp ; opt_exp ) stmt

│ . . .
opt_expr  expr │ ε

17

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫תרגום מונחה תחביר‬

‫(‪)Syntax Directed Translation‬‬
‫• מבנה (‪ – )construct‬תמנית או תת‪-‬מחרוזת הנגזרת ע"י משתנה‬
‫• תכונה (‪ – )attribute‬מציינת גודל או מאפיין הקשור למבנה כגון‬
‫טיפוס‪ ,‬מחרוזת‪ ,‬מקום בזיכרון וכד'‬
‫• תרגום מונחה דקדוק (‪ – )syntax directed translation‬דקדוק בו‬
‫התכונות והתרגום של מבנה מוגדרות באמצעות התכונות של‬
‫המבנים המרכיבים אותו ע"פ כלל הגזירה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪18‬‬

‫הגדרה מונחית תחביר‬

‫(‪)Syntax Directed Definition‬‬
‫• משתמשת בדקדוק חסר הקשר ע"מ להביע את מבנה התחביר של‬
‫השפה‬
‫• לכל סמל בדקדוק מקושרת קבוצת תכונות‬
‫• לכל כלל גזירה מקושרים כללי משמעות (‪ )semantic rules‬לחישוב‬
‫התכונות של הסמל שבצד השמאלי מתוך תכונות הצד הימני‬
‫אם ‪ X‬הוא סמל (תמנית או משתנה)‬
‫ואם ‪ a‬הינה תכונה שלו‬
‫ואם ‪ n‬הינו צומת בעץ פריסה‪,‬‬
‫‪ X.a‬יסמן את התכונה ‪ a‬של ‪ X‬בצומת ‪n‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪19‬‬

– ‫דוגמה‬
‫תרגום ביטוי פנימי לביטוי סופיות‬
‫כללי גזירה‬

‫כללי משמעות‬

expr  expr1 + term

expr.t := expr1.t ║ term.t ║ ‘+’

expr  expr1 - term

expr.t := expr1.t ║ term.t ║ ‘-’

expr  term

expr.t := term.t

term  0

term.t := ‘0’

term  1

term.t := ‘1’

...

...

term  9

term.t := ‘9’

20

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ פריסה מקושט‬
‫(‪)Annotated Parse Tree‬‬
‫עץ פריסה שבו נכתבות התכונות של כל צומת‬

‫‪95−2+‬‬
‫‪= 2‬‬

‫=‬

‫‪expr.t‬‬
‫‪= 95−‬‬

‫‪term.t‬‬
‫‪= 5‬‬

‫‪2‬‬
‫איתן אביאור‬

‫‪+‬‬

‫‪term.t‬‬

‫‪5‬‬
‫תורת הקומפילציה‬

‫‪expr.t‬‬
‫‪= 9‬‬

‫‪−‬‬

‫‪term.t‬‬

‫‪9‬‬
‫‪21‬‬

‫דוגמה – רובוט‬
:‫שפה להנחיית רובוט המבצע בכל פעם צעד באחד מארבעה כיוונים‬
:‫הדקדוק‬
seq  seq instr │ begin
instr  east │ north │ west │ south
:‫דוגמה‬
begin west south east east east north north
(2, 1)
(-1,0)

west

begin
(0,0)

north

south
(-1,-1)
22

north
east

east

east

‫תורת הקומפילציה‬

(2,-1)
‫איתן אביאור‬

‫דוגמה – רובוט‬
‫הגדרה מונחית תחביר‬
Production
seq  begin
seq  seq1 instr
instr  east

instr  north
instr  west
23

instr  south

Semantic Rules
seq.x := 0
seq.y := 0
seq.x := seq1.x + instr.dx
seq.y := seq1.y + instr.dy
instr.dx := 1
instr.dy := 0
instr.dx := 0
instr.dy := 1
instr.dx := -1
instr.dy := 0
instr.dx := 0
‫תורת הקומפילציה‬
‫איתן אביאור‬
instr.dy := -1

‫דוגמה – רובוט‬
‫עץ מקושט‬
begin west south

seq.x = -1
seq.y = -1

seq.x = -1
seq.y = 0

24

instr.dx = 0
instr.dy = -1

seq.x = 0
seq.y = 0

instr.dx = -1
instr.dy = 0

begin

west
‫תורת הקומפילציה‬

south

‫איתן אביאור‬

‫סכמת תרגום‬
‫(‪)Translation Scheme‬‬
‫דקדוק חסר הקשר בו משולבים קטעי תוכנית הנקראים‬
‫פעולות משמעות (‪ )semantic actions‬בצדדים הימניים של כללי‬
‫הגזירה‪.‬‬
‫דומה להגדרה מונחית תחביר‪ ,‬אלא שסדר חישוב המשמעויות‬
‫מצויין במפורש‪.‬‬
‫לדוגמה‪:‬‬
‫בדקדוק המקבל ביטויים עם תחיליות ואשר מטרתו לייצר ביטוי פנימי‪:‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪25‬‬

‫עץ פריסה של סכימת תרגום‬
‫הכלל‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫מוצג בעץ הפריסה‪:‬‬
‫‪rest‬‬

‫‪rest1‬‬

‫איתן אביאור‬

‫})’‪{print (‘+‬‬

‫תורת הקומפילציה‬

‫‪term‬‬

‫‪+‬‬

‫‪26‬‬

‫הגדרה מונחית דקדוק פשוטה‬

‫(‪)Simple Syntax Directed Definition‬‬
‫הגדרה מונחית דקדוק בה התרגום של כל צד שמאל הינו שרשור‬
‫התרגומים של הצד הימני (בצרוף אופציונלי של תווים נוספים)‬
‫נקראת פשוטה (‪.)simple‬‬
‫דוגמאות‪:‬‬
‫‪expr  expr1 + term‬‬
‫‪ .1‬פנימי לסופיות‪:‬‬
‫’‪expr.t := expr1.t ║ term.t ║ ‘+‬‬
‫‪rest  + term rest1‬‬
‫‪ .2‬תחיליות לפנימי‪:‬‬
‫‪rest.t := term.t ║ ‘+’ ║ rest1.t‬‬
‫סכמות התרגום המתאימות‪:‬‬
‫} )’‪expr  expr1 + term { print (‘+‬‬
‫‪.1‬‬
‫‪rest  + term { print (‘+’) } rest1‬‬
‫‪.2‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪27‬‬

‫סכמת התרגום של ביטויים‬
expr
expr
expr
term
term
. .
term

28






.


expr + term
expr - term
term
0
1

{ print (‘+’) }
{ print (‘-’) }

9

{ print (‘9’) }

{ print (‘0’) }
{ print (‘1’) }

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫עץ הפריסה והפעולות של ביטוי‬
‫הביטוי ‪ 9 – 5 + 2‬יתורגם לביטוי ‪ 9 5 – 2 +‬ע"י העץ הבא‪:‬‬
‫‪expr‬‬
‫})’‪{print(‘+‬‬

‫‪+‬‬

‫‪term‬‬
‫})’‪{print(‘2‬‬

‫‪expr‬‬

‫‪2‬‬

‫‪-‬‬

‫})’‪{print(‘-‬‬
‫‪term‬‬
‫})’‪{print(‘5‬‬

‫‪expr‬‬
‫‪5‬‬

‫‪term‬‬
‫})’‪{print(‘9‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪9‬‬
‫‪29‬‬

‫פריסה (‪)Parsing‬‬
‫• פריסה (‪ − )parsing‬תהליך הבוחן האם מחרוזת תמניות יכולה‬
‫להיווצר ע"י דקדוק‪.‬‬
‫• פורס (‪ − )parser‬השלב המבצע את הניתוח התחבירי ומסוגל‬
‫לבנות (בפועל או בכוח) את עץ הפריסה‪.‬‬
‫• טכניקות לבניית פורס‪:‬‬
‫– מתרגם מונחה דקדוק (‪)syntax directed translator‬‬
‫─ נראה דוגמה להלן‬
‫– כלי תוכנה הבונה פורס מתוך סכימת התרגום ( ‪translation‬‬
‫‪ ─ )scheme‬בהמשך הקורס‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪30‬‬

‫סיבוכיות הפריסה‬
‫משפט‪:‬‬
‫לכל דקדוק חסר הקשר ניתן לבנות פורס (‪)parser‬‬
‫בעל סיבוכיות זמן )‪.O(n3‬‬
‫בפועל‪:‬‬
‫הפורסים של רוב שפות התכנות מבצעים מעבר יחיד‬
‫על הקלט‪ ,‬עם הצצה על תמנית אחת קדימה‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪31‬‬

‫כיווני הפריסה‬
‫• מלמעלה למטה (‪ − )top-down‬פורס המתחיל מסמל התחלה‬
‫(‪ )start symbol‬ובונה (או סורק) את עץ הפריסה כלפי מטה‬
‫– ניתן לבנות ידנית פורסים יעילים בשיטה זו‬

‫• מלמטה למעלה (‪ − )bottom-up‬פורס המתחיל מהתמניות שבעלים‬
‫ובונה (או סורק) את עץ הפריסה כלפי מעלה‬
‫– מתאים יותר לכלים אוטומטים ליצירת פורסים‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪32‬‬

‫פריסה מלמעלה למטה‬
‫(‪)Top-Down Parsing‬‬
‫‪ .1‬התחל בשורש‬
‫‪ .2‬חזור ‪:‬‬
‫‪ 2.1‬בצומת ‪ ,n‬המסומן ע"י משתנה ‪ A‬בחר את אחד מכללי הגזירה‬
‫עבור ‪ A‬ובנה את הצאצאים של ‪ n‬ע"פ הצד הימני של הכלל‬
‫‪ 2.2‬מצא את הצומת הבא לפריסה או עצור‬
‫•‬
‫•‬
‫•‬
‫•‬

‫ישנם דקדוקים עבורם האלגוריתם הנ"ל יכול להתבצע בסריקה בודדת של הקלט‬
‫הסמל הבא (‪ − )lookahead symbol‬התמנית הבאה לקריאה מהקלט‬
‫פריסה מנבאת (‪ − )predictive parsing‬ניתן תמיד לבחור את כלל הגזירה‬
‫המתאים ע"פ הסמל הבא‬
‫במקרה הכללי ‪ −‬יש לעבור בשיטת הניסוי והטעיה‪/‬תעיה ולבצע נסיגה‬
‫(‪ )backtracking‬בעת הצורך‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪33‬‬

‫פריסה יורדת רקורסיבית‬

‫(‪)Recursive Descent Parsing‬‬
‫שיטה של ניתוח תחביר מלמעלה למטה‬
‫• לכל משתנה בדקדוק קיים נוהל בתוכנית‬
‫• בכל פעם שיש לגזור משתנה קוראים לנוהל המתאים‬
‫• הנהלים מבצעים קריאות רקורסיביות זה לזה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪34‬‬

Pascal ‫דוגמה – חלק מתחביר‬
‫להגדרת טיפוסי משתנים‬
 simple
│ ^ id
│ array [ simple ] of type
simple  integer
│ char
│ num dotdot num
type

35

‫תמניות הניתוח הלקסיקאלי‬
D
::= 0−9
L
::= a−z
U
::= A−Z
A
::= L │ U │ _
id
::= A(AD)
num ::= D+
dotdot ::= ..

‫תורת הקומפילציה‬

‫איתן אביאור‬

‫דוגמה לפורס יורד רקורסיבית‬
void match (token t)
void type ()
{
{
if ( lookahead == t )
if
( lookahead == integer ||
lookahead = nexttoken();
lookahead == char
||
else error();
lookahead == num
)
}
simple();
void simple ( )
else if ( lookahead == “^”) {
{
match (“^”);
if ( lookahead == integer )
match ( id );
match (integer);
} else if ( lookahead == array ) {
else if ( lookahead == char )
match (array);
match (char);
match (“[“);
else if ( lookahead == num ) {
simple() ;
match (num);
match (“]”);
match (dotdot);
match (of);
match (num);
type();
} else error();
} else error();
36
‫תורת הקומפילציה‬
‫איתן אביאור‬
}
}

‫‪FIRST‬‬
‫יהי ‪ ‬צד ימין של כלל גזירה‬
‫הגדרה‬
‫)‪ FIRST(‬הינה קבוצת התמניות המופיעות כסמל הראשון‬
‫באחד או יותר מחרוזות הנוצרות מ‪. -‬‬
‫אם ‪ ‬הינה ‪ ε‬או יכולה לייצר ‪ ε‬אזי גם ‪ ε‬שייך ל‪.FIRST()-‬‬
‫דוגמה‬
‫)‪FIRST (simple‬‬
‫} ‪= { integer, char, num‬‬
‫) ‪FIRST ( ^ id‬‬
‫}^{=‬
‫} ‪FIRST ( array [ simple ] of type ) = { array‬‬
‫בהמשך הקורס נראה אלגוריתם לבניית ‪FIRST‬‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪37‬‬

‫פריסה יורדת רקורסיבית ללא נסיגות‬

‫(‪Recursive Descent Parsing‬‬
‫‪)Without Backtracking‬‬
‫אם למשתנה ‪ A‬ישנם שניים (או יותר) כללי גזירה‪:‬‬
‫‪A‬‬
‫‪A‬‬
‫ואם ‪FIRST ()  FIRST () = ‬‬
‫אזי ניתן תמיד להשתמש בסמל הבא (‪)lookahead‬‬
‫ע"מ להכריע באיזה כלל גזירה יש להשתמש‪,‬‬
‫ולקבל פריסה יורדת רקורסיבית ללא נסיגות‪.‬‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪38‬‬

‫פורס מנבא‬
‫(‪)Predictive Parser‬‬
‫פורס מנבא (‪ )predictive parser‬מורכב מאוסף של שגרות שכל אחת מהן מתאימה‬
‫למשתנה מסוים ומופעלת בעת הצורך לגזור אותו‪ .‬השגרה של ‪ A‬תפעל כדלקמן‪:‬‬
‫‪ .1‬בחר כלל גזירה כדלקמן‪:‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• אם הסמל הבא שייך ל‪ FIRST()-‬השתמש בכלל ‪A  ‬‬
‫• ‪...‬‬
‫• אם הסמל הבא לא שייך לשום ‪ FIRST‬של צד ימני המתאים ל‪:A-‬‬
‫– אם יש כלל ‪ A  ε‬השתמש בו‪ ,‬אחרת ─ שגיאה‬
‫‪ .2‬חיקוי צד ימין של כלל הגזירה המתאים‪:‬‬
‫• משתנה ─ קריאה לשגרה המתאימה למשתנה‬
‫• תמנית ─ וידוא שהתמנית מופיעה בקלט‪ ,‬אחרת ─ שגיאה‬

‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪39‬‬

‫תרגום בעזרת פריסה מנבאת‬
‫כפי שסכמת תרגום (‪ )translation scheme‬מתקבלת מדקדוק ע"י הוספת‬
‫פעולות משמעות (‪ )semantic action‬כך ניתן לקבל מתרגם מונחה דקדוק‬
‫(‪ )syntax directed translator‬מתוך פורס מנבא ע"י הוספת שגרות‬
‫לביצוע‪:‬‬
‫• אלגוריתם כללי להוספת פעולות משמעות נראה בהמשך הקורס‬
‫• כאשר סכמת התרגום פשוטה‪ ,‬ואיננה מייחסת תכונות (‪)attributes‬‬
‫למשתנים ניתן לעשות זאת באופן הבא‪:‬‬
‫‪ .1‬בנה פורס מנבא תוך התעלמות מפעולות המשמעות‬
‫‪ .2‬העתק את פעולות המשמעות מסכמת התרגום לפורס‪:‬‬
‫‪ 2.1‬אם פעולת המשמעות מופיעה בדקדוק לאחר סמל ‪ X‬בכלל‬
‫גזירה ‪ P‬אזי היא תועתק לשגרה המתאימה מיד לאחר הקוד‬
‫המיישם את הסמל ‪X‬‬
‫‪ 2.2‬אם היא מופיעה בתחילת כלל הגזירה‪ ,‬היא תועתק לפני הקוד‬
‫המיישם את כלל הגזירה‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪40‬‬

‫רקורסיה שמאלית‬
‫(‪)Left Recursion‬‬
‫‪expr  expr + term‬‬
‫כלל מהצורה‪:‬‬
‫יגרום לרקורסיה אינסופית של הפורס היורד רקורסיבית‬
‫ביטול רקורסיה שמאלית‪:‬‬
‫‪A  A │‬‬
‫אם קיים כלל‬
‫כאשר ‪ A‬איננו ההתחלה לא של ‪ ‬ולא של ‪ ‬נחליף אותו בכללים‪:‬‬
‫‪A  R‬‬
‫‪R  R │ ε‬‬
‫המכילים רק רקורסיה ימנית‪ ,‬שאיננה גורמת לפורס לרקורסיה‬
‫אינסופית מפני שכל הפעלת רמה ברקורסיה "זוללת" חלק מהקלט‪.‬‬
‫בהמשך הקורס נרחיב את הנושא‬
‫איתן אביאור‬

‫תורת הקומפילציה‬

‫‪41‬‬

‫תום פרק ‪2‬‬
‫– סעיף ‪2.5‬‬
‫– סעיפים ‪2.9 − 2.6‬‬

‫איתן אביאור‬

‫─ תרגול‬
‫─ קריאה עצמית‬

‫תורת הקומפילציה‬

‫‪42‬‬