שפה מומצאת — 5 שלבים, Dry Run, Symbol Table
שפה מומצאת — המחשבון קרב
שיעור זה הוא הכי חשוב בקורס לכנס המבחנים. מחשבון הקרב = שפה שמעולם לא ראית + קוד + 20 שאלות + 45 דקות לחץ. מי שיש לו מתודולוגיה = עובר. מי שמנסה "לנחש" = נכשל.
- 5 השלבים — סקר מהיר → מיפוי → Trace דוגמה → Dry Run → ניהול זמן
- Pattern Recognition — 8 Building Blocks בכל שפה, טבלת operators
- Symbol Table — כלי החובה לכל Dry Run: מבנה, לולאות, לולאות מקוננות
- Dry Run — ביצוע ידני שורה-שורה: Zenith, Kova, NovaCal
- Stack Frames — Frame לכל פונקציה, עץ קריאות לרקורסיה
- שפת Zenith — LET, FOR/END FOR, IF THEN/END IF, FUNC, PRINT
- שפת Kova — var, :=, @, @@, ?, fn, >>
- שפת NovaCal — Assembly-style: STORE, LOAD, ADD, SAVE, IFGT, JUMP
- ניהול זמן — 3 דקות max, סמן ועבור, חזור בסוף
5 השלבים: המתודולוגיה המדעית
כל מועמד שמגיע ל-Gamma Computer Test ללא מתודולוגיה — מאבד זמן. כל מועמד עם 5 השלבים — יודע מה לעשות בכל רגע נתון.
| שלב | שם | מה עושים | זמן מומלץ |
|---|---|---|---|
| 1 | סקר מהיר | קרא את כל המפרט פעם אחת ללא עצירה. מטרה: "מה יש כאן?" | 5-7 דקות |
| 2 | מיפוי Pattern | זהה: Assignment? לולאה? תנאי? פונקציה? מלא טבלת Pattern | 3-5 דקות |
| 3 | Trace דוגמה | מצא קטע קוד פשוט במפרט ו-trace אותו ידנית — ודא שהבנת | 5-7 דקות |
| 4 | Dry Run + Symbol Table | לכל שאלה: בנה Symbol Table, עקוב שורה-שורה, ענה | 2-3 דקות/שאלה |
| 5 | ניהול זמן | שאלה קשה יותר מ-3 דקות? סמן ועבור הלאה. חזור בסוף. | תמידי |
! לא לפרש לפי Python! ›
הטעות הנפוצה ביותר: מיד "מתרגמים" את השפה המומצאת לPython בראש.
LOOP i FROM 1 TO 5 — מיד: "זה for i in range(1,5)" — אבל TO 5 כולל 5 או לא? חייב לבדוק בדוגמאות המפרט!
כלל: אל תניח — ודא. בדוק תמיד בדוגמות המפרט אם הגבול כולל או לא.
טבלת Pattern — מלא בכנס
| פעולה | Syntax בשפה זו |
|---|---|
| Assignment | ?? |
| הדפסה | ?? |
| תנאי (if) | ?? |
| לולאה ספירה | ?? |
| לולאה תנאי (while) | ?? |
| הגדרת פונקציה | ?? |
| גישה למערך | ?? |
| שוויון (==) | ?? |
Symbol Table: הכלי המרכזי
Symbol Table = טבלה שרושמים בה כל משתנה ואת הערך הנוכחי שלו בכל נקודת זמן. בלי Symbol Table = שוכחים ערכים → תשובות שגויות.
Dry Run על שפת Zenith — דוגמה מלאה
LET sum = 0
LET count = 0
FOR i = 1 TO 10
IF i MOD 2 = 0 THEN
SET sum TO sum + i
SET count TO count + 1
END IF
END FOR
PRINT sum
PRINT counti MOD 2 = 0 → i זוגי. לולאה i=1..10:
i=2: sum=0+2=2, count=1 | i=4: sum=2+4=6, count=2 | i=6: sum=6+6=12, count=3 | i=8: sum=12+8=20, count=4 | i=10: sum=20+10=30, count=5
פלט: PRINT sum → 30 | PRINT count → 5
מה עושה הקוד? → מחשב סכום ומספר המספרים הזוגיים בטווח 1–10.
Symbol Table ללולאות מקוננות
SET count TO 0
LOOP i FROM 1 TO 3
LOOP j FROM 1 TO i
ADD count BY 1
ENDLOOP
ENDLOOP
OUTPUT countפלט: 6 | נוסחה: 1+2+3 = n*(n+1)/2 = 3*4/2 = 6
LET x = 1
FOR i = 1 TO 4
SET x TO x * 2
END FOR
PRINT xמה הפלט?שלוש שפות: Zenith, Kova, NovaCal
כל שפה בכנס תהיה שונה. המטרה: להכיר 3 סוגי Syntax שונים בתכלית — כדי שכל שפה חדשה תיראה מוכרת.
שפת Zenith — Syntax מילולי
LET <name> = <value> ; הגדרת משתנה
SET <name> TO <expr> ; עדכון ערך
FOR <var> = s TO e ... END FOR ; כולל e!
WHILE cond ... END WHILE
IF cond THEN ... ELSE ... END IF
FUNC f(p) ... RETURN v ... END FUNC
PRINT x
arr[i] / arr.SIZE
= (eq) / <> (neq) / MOD (%) / ^ (power)שפת Kova — Syntax סמלי
var x : num ; הגדרת משתנה
x := expr ; השמה
? cond { } ; if
? cond { } ~ { } ; if/else (~ = else)
?? cond { } ; elseif
@ var in s..e { } ; for loop (inclusive!)
@@ cond { } ; while loop
fn f(p:num)->num { return v; }
>> x ; הדפסה
|arr| ; גודל מערך
== / != / && / || / !שפת NovaCal — Assembly Style
STORE <val> IN <name> ; x = val
COPY x TO y ; y = x
SWAP x y ; swap
LOAD x → ACC = x ; load to accumulator
ADD x → ACC += x
SUB x → ACC -= x
SAVE x → x = ACC
IFGT a b JUMP <label> ; if a > b: goto label
GOTO <label>
EMIT x ; print(x)// NovaCal Dry Run:
STORE 1 IN i // i=1
STORE 0 IN total // total=0
LOOP_START:
IFGT i 5 JUMP LOOP_END // i>5? jump
LOAD total
ADD i
SAVE total // total += i
LOAD i
ADD i
SAVE i // i = i+i = i*2 !!
GOTO LOOP_START
LOOP_END:
EMIT total
// Symbol Table:
// init: i=1, total=0
// iter 1: IFGT 1>5→F → total=0+1=1, i=1+1=2
// iter 2: IFGT 2>5→F → total=1+2=3, i=2+2=4
// iter 3: IFGT 4>5→F → total=3+4=7, i=4+4=8
// iter 4: IFGT 8>5→T → JUMP LOOP_END
// EMIT total → פלט: 7Stack Frames: מעקב פונקציות ורקורסיה
כשפונקציה קוראת לפונקציה — נוצר Stack Frame. כל Frame מחזיק: שם הפונקציה, פרמטרים, משתנים מקומיים. בזמן Dry Run: ציר כל Frame כעמודה נפרדת.
// Zenith — פקטוריאל רקורסיבי
FUNC fact(n)
IF n <= 1 THEN
RETURN 1
END IF
RETURN n * fact(n-1)
END FUNC
PRINT fact(4)
// Call Stack:
// fact(4): 4>1 → RETURN 4 * fact(3)
// fact(3): 3>1 → RETURN 3 * fact(2)
// fact(2): 2>1 → RETURN 2 * fact(1)
// fact(1): n<=1 → RETURN 1 ← BASE CASE
// Rewinding:
// fact(1) = 1
// fact(2) = 2*1 = 2
// fact(3) = 3*2 = 6
// fact(4) = 4*6 = 24
// PRINT fact(4) → 24! Recursive Dry Run — הטעות הנפוצה ›
מנסים לעקוב בסדר "מלמעלה למטה" ומאבדים את ה-Thread.
✅ נכון: בנה עץ קריאות → מלא ערכים מהעלים כלפי מעלה (Leaves First).
❌ שגוי: לנסות לעקוב שורה-שורה ב"קפיצות" בין frames.
כלל: כל call = node בעץ. מלא leaves תחילה, אחר כך חשב parents.
LET arr[6]
SET arr[0]=2 arr[1]=5 arr[2]=1
SET arr[3]=8 arr[4]=3 arr[5]=7
LET result = arr[0]
FOR i = 1 TO 5
IF arr[i] MOD 2 = 0 THEN
IF arr[i] > result THEN
SET result TO arr[i]
END IF
END IF
END FOR
PRINT resultמה הפלט?אתגר מעשי — שפה מומצאת: Lexer ו-Symbol Table
שיא השיעור: לבנות ולתקן מערכות אמיתיות — מפרשים, פרוטוקולים, מכונות. פתרו את החובה ואז את האתגר; ההגשה נבדקת אוטומטית מול מקרי-קצה נסתרים.
סיכום השיעור
- 5 שלבים: סקר מהיר → מיפוי Pattern → Trace דוגמה → Dry Run+Symbol Table → ניהול זמן
- Pattern Recognition: 8 Building Blocks בכל שפה + טבלת operators
- Symbol Table: כלי חובה לכל Dry Run. לולאות = עמודה נוספת לloop variable
- שפת Zenith: LET/SET, FOR-END FOR (כולל!), FUNC-END FUNC, MOD, ^
- שפת Kova: var, :=, @(for), @@(while), ?(if), fn, >>, |arr|
- שפת NovaCal: STORE, LOAD, ADD, SUB, SAVE, IFGT, JUMP, EMIT
- Stack Frames: frame לכל פונקציה, עץ קריאות לרקורסיה, leaves תחילה
- ניהול זמן: 3 דקות max, סמן ועבור הלאה, חזור בסוף
לפני שיעור 12: עשה Dry Run על כל 3 שפות — עוד 5 קטעי קוד כל שפה. כתוב Symbol Table על נייר — לא בראש. בנה עץ קריאות לfib(6) ולfact(5).
שאלות תרגול ותשובות (10)
שאלה 1 · מה יודפס? (שפת Zenith — FOR כולל את הגבול העליון)
LET sum = 0
FOR i = 1 TO 10
IF i MOD 2 = 0 THEN
SET sum TO sum + i
END IF
END FOR
PRINT sum- א. 25
- ב. 30
- ג. 20
- ד. 55
הזוגיים 2+4+6+8+10 = 30. שימו לב ש-TO 10 כולל את 10.
שאלה 2 · מה יודפס? (Zenith — לולאה פנימית התלויה ב-i)
SET count TO 0
LOOP i FROM 1 TO 3
LOOP j FROM 1 TO i
ADD count BY 1
ENDLOOP
ENDLOOP
OUTPUT count- א. 3
- ב. 6
- ג. 9
- ד. 12
1+2+3 = 6 — הפנימית תלויה ב-i, ולכן n(n+1)/2 ולא n².
שאלה 3 · מה יודפס? (NovaCal — עקבו אחרי ה-ACC)
STORE 1 IN i
STORE 0 IN total
LOOP_START:
IFGT i 5 JUMP LOOP_END
LOAD total
ADD i
SAVE total
LOAD i
ADD i
SAVE i
GOTO LOOP_START
LOOP_END:
EMIT total- א. 7
- ב. 15
- ג. 8
- ד. 5
i מוכפל בכל סיבוב (1,2,4,8): total = 1+2+4 = 7, ואז 8>5 קופץ החוצה.
שאלה 4 · מה עושה רצף הפקודות הזה ב-NovaCal?
LOAD x ADD x SAVE x
- א. x = x + 1
- ב. x = x * 2
- ג. ACC = 0
- ד. מחליף בין x ל-ACC
ACC נטען ב-x ואז מוסיפים לו שוב x — כלומר x = x + x.
שאלה 5 · מה יודפס? (Kova — @ הוא לולאת for וטווח a..b הוא inclusive)
var t : num
t := 0
@ i in 1..4 {
t := t + i * i
}
>> t- א. 14
- ב. 30
- ג. 20
- ד. 10
1+4+9+16 = 30 — הטווח כולל את 4.
שאלה 6 · לכמה טוקנים מפרק ה-Tokenizer את השורה הבאה ב-Kova?
x := y == 3
- א. 4 טוקנים: x , := , y , == , 3 — כלומר 5
- ב. 5 טוקנים: x, :=, y, ==, 3
- ג. 7 טוקנים: כל תו בנפרד
- ד. 3 טוקנים
Maximal Munch — := ו-== נקראים כיחידה אחת כל אחד, ולא כשני סימנים נפרדים.
שאלה 7 · מה מחזירה הקריאה f(4)?
FUNC f(n)
IF n = 1 THEN
RETURN 1
END IF
RETURN n * f(n - 1)
END FUNC
PRINT f(4)- א. 10
- ב. 16
- ג. 24
- ד. 4
פריסה והצבה חזרה: f(1)=1 → f(2)=2 → f(3)=6 → f(4)=24.
שאלה 8 · כמה קריאות (frames) ייפתחו בסך הכול עבור g(4), כולל הקריאה הראשונה?
FUNC g(n)
IF n <= 1 THEN
RETURN n
END IF
RETURN g(n - 1) + g(n - 2)
END FUNC- א. 4
- ב. 5
- ג. 7
- ד. 9
קריאה כפולה בונה עץ: g(4)→g(3),g(2)... בסך הכול 9 קריאות — לכן Memoization חיונית.
שאלה 9 · מה יודפס? (שימו לב לתנאי העצירה של הלולאה)
LET x = 10
WHILE x > 0
SET x TO x - 3
END WHILE
PRINT x- א. 0
- ב. 1
- ג. -2
- ד. 4
10→7→4→1→-2; בערך 1 התנאי עדיין מתקיים, ולכן הלולאה מבצעת סיבוב נוסף.
שאלה 10 · מה יודפס? (Kova — ~ הוא else)
var n : num
n := 7
? n MOD 2 == 0 {
>> n / 2
} ~ {
>> n * 3 + 1
}- א. 3
- ב. 22
- ג. 7
- ד. 14
7 אי-זוגי, לכן מתבצע ענף ה-else: 7*3+1 = 22.