forked from CS234319/safot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsteps.tex
6553 lines (5603 loc) · 527 KB
/
steps.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
§ שָׁלוֹם, עוֹלָם!
תהליך הכתיבה של תכנית מחשב, כרוך בלא מעט עבודה "מנהלתית". יש להשתמש ב\עורך
או ב\מונח{סביבת פיתוח אינטראקטיבית} בכדי להכין את הקובץ או הקבצים שבהם תמצא
התכנית~(א). יש להכיר מעט את \מונח[מערכת הפעלה]{מערכת ההפעלה}, כדי לדעת כיצד
לנהל את הקבצים הללו~(ב), ויש לדעת כיצד להפעיל את ה\מהדר~(ג).
כמובן נדרשת גם יכולת התמודדות עם הודעות שגיאה ושאר התאוננויות של ה\מהדר~(ד),
ולאחר שאלו טופלנה, יש לדעת כיצד יש להריץ את התכנית~(ה). אין תימה על כן שהצעד
הראשון בלימוד מעשי של שפת תכנות, כל שפת תכנות, הוא הפעלת המיומנות הללו לשם
כתיבת תכנית פשוטה בשפה. תכנית "שָׁלוֹם, עוֹלָם!" (ובאנגלית \אנגלית{‟Hello, World!"
program}) היא תכנית פשוטה כזו. כל אשר היא עושה הוא להציג את ה\סדרית "שָׁלוֹם,
עוֹלָם!" בשפה האנגלית על פני הצג. מסורת עתיקה היא לכתוב כתכנית ראשונה דווקא
תכנית זו.
אדגים זאת בזריזות, וכיוון שמקורה של המסורת הוא בספר הלימוד של שפת \סי, אכתוב
ראשית את התכנית "שָׁלוֹם, עוֹלָם!" בשפה זו.
מטבע הדברים, ההדגמה תהיה בעבור סביבת חישוב מסויימת, סביבת החישוב שלי, הכוללת
מערכת הפעלה מסוג גנו/לינוקס, עימה אתקשר באמצעות \מונח[מעטפת פקודות]{מעטפת
הפקודות} \אנגלית{bash}.
\begin{english}
\let\ttfamily=\listingsfont
\begin{CPP}
() ; .
\end{CPP}
\end{english}
לעומת זאת, בשתי התכניות שלעיל, אין סימני פעולה כלל.
\begin{קוד}
\bash[verbose,script,scriptFile=make-hello-c.sh]
rm -f hello.c; cat << EOF > hello.c
/*
** hello.c: My first C program; it prints
** "Hello, World!", and dies.
*/
#include <stdio.h>
int main(int argc, char *argv[], char **envp) {
printf("Hello, World!\n");
return 0;
}
EOF
\END
\end{קוד}
{\קטן
\noindent\hrulefill
תזכורת, ב-bash הסימן \% מציין אֶת הַ\זרז. אם אתה מכיר מעט את bash או
\מונח{מעטפת פקודות}
אחרת כלשהי הפועלת בסביבת יוניקס או בסביבה דמויית יוניקס, תוכל ודאי
לזהות את שתי ה\פקודות שכתבתי כאן: מחיקת גירסה קודמת של הקובץ אם זו קיימת,
ויצירת הקובץ מבראשית. ה\פקודה \קד{cat} מעתיקה מה\מונח[קלט סטנדרטי]{קלט
הסטנדרטי} אל ה\מונח[פלט סטנדרטי]{פלט הסטנדרטי}, ואילו \מונח[מטבע לשון
תכנותית]{מטבע הלשון התכנותית}
\begin{קוד}
\cpp{cat << EOF}
\end{קוד}
משמעו העתקה מהקלט הסטנדרטי עד אֲשֶׁר בקלט תופיע שורה שבה מופיעה המילה
\קד{EOF} לבדה.
\par\noindent\hrulefill}
דרך אחרת, יעילה יותר להכין את הקובץ, היא להשתמש ב\עורך. הנה למשל \עע איור וים
מדגים שימוש בעורך \שי{gvim}, העורך החביב עלי, לשם הכנת הקובץ \קד{hello.c}.
\begin{איור}[!htbp]
\begin{center}
\includegraphics[width=0.8\textwidth]{hello-c-with-gvim.jpg}
\includegraphics[width=0.8\textwidth]{hello-c-with-gedit.jpg}
\end{center}
\כיתוב|עריכת קובץ המכיל תכנית \סי באמצעות העורך gvim|
\תגית|איור:וים|
\end{איור}
בין כך, ובין כך, לאחר שהקובץ נוצר, עלי להדר אותו. כדי להדר את הקובץ בסביבת
החישוב שלי, אכתוב:
\bash[script]
cc hello.c
\END
ואחר כך, כל שנותר לי לעשות כדי להריץ את התכנית, הוא לכתוב:
\bash[verbose,script,stdout]
./a.out
\END
עיניך הרואות, סדרת הפעולות הנדרשת בכדי ליצור את התכנית הפשוטה הזו, להדרה
ולהפעילה, עשוייה להיות מעט מורכבת. אבל, אין מנוס מכך: התנסות בלתי אמצעית
בפעולות אלו חיונית לשם רכישת יכולת שימוש בשפה.
מטבע הדברים, ספר זה לא יוכל להוות תחליף להתנסות האישית הזו בסביבת המחשוב
המיוחדת שלך. יהיה עליך לעשות זאת בעצמך, ולחזור ולעשות זאת מחדש בעבור כל שפת
תכנות שתלמד, ובעבור כל סביבת מחשב עליה תבחר לעבוד.
אולם, עצם ההסתכלות בתכנית "שָׁלוֹם, עוֹלָם!" ובתכניות אחרות, קצרות ככל שתהיינה,
יכולה ללמד את המעיין רבות על השפה בה הן כתובות, על הדקדוק שלה, ואולי על כמה
עקרונות בתכנון שלה. בפרק זה נכיר כמה כלים שיסייעו לנו בלימוד הזה, ונאמן את
עיננו לבחון תכניות, במיוחד תכניות הכתובות בשפת תכנות שאינה מוכרת לנו, לעומקן.
ראשית, נאתר את המרכיבים הדקדוקיים היסודיים, ונראה שאלו מופיעים שוב ושוב בשפות
תכנות שונות. אחר כך, נגלה שבתכנון דקדוק בעבור שפות תכנות שונות, יש שאלות
מסויימות אשר חוזרות על עצמן שוב ושוב.
כך למשל, הגדרת כל שפת תכנות חייבת להתמודד עם הצורך לצייד את המתכנת במנגנון
לכתיבת \הערות. אנו נראה כי אף הפתרונות בהם בוחרים מתכנני השפות בעבור בעיות אלו
נוטים לחזור על עצמם. ובאמת, מספר הדרכים השונות שבהן ניתן לכתוב \הערות בשפות
תכנות שונות אינו רב.
הכרה של השאלות הללו---צמתי ההחלטה בזמן תכנון השפה, ומרחב הפתרונות המוכרים
לשאלות, יסייעו לנו לזהות בקלות, מתוך הצצה חטופה לפעמים, בפתרון בו בחר מתכנן
השפה.
§ מרכיבים דקדוקיים יסודיים
מקובל להציג תכניות באופן המבליט את תפקידם השונה של המרכיבים הדקדוקיים היסודיים
בשפה. הנה למשל, אם נסתכל ב\עע איור וים נראה שהעורך gvim משתמש בצבעים שונים לשם
הצגת הקובץ \קד{hello.c}.
סביר שה\עורך או סביבת הפיתוח האינטראקטיבית שלך אף הם משתמשים בהבלטה ויזואלית
מעין זו המודגמת באיור. למעשה, הבלטה ויזואלית של מרכיבים דקדוקיים שונים היא כה
נפוצה, עד שישנן \ספריות תכנה המשרתות צורך זה.
ב\לינוקס למשל, ישנה \ספריה בשם gtksourceview התומכת בהבלטה דקדוקית של שפות
שונות. התקנה רגילה של gtksourceview תומכת ביותר משבעים שפות תכנות. היכולת
לתמוך במספר כה רב של שפות מוסברת בכך שרשימת המרכיבים היסודיים השונים אינה
ארוכה, והיא בדרך כלל מכילה שישה סוגים עיקריים:
\begin{ספרור}
✦ \מילולונים מסוג של מספר שלם, מספר ממשי, תו ו\סדרית.
✦ \הערות
✦ \מונח[מילה שמורה]{מילים שמורות}
✦ \מזהים
✦ סימני פעולה שונים, כגון אופרטורים מתימטיים והצבה.
✦ סימני פיסוק שונים, המסייעים לקורא ול\מהדר לזהות את חלקי התכנית השונים.
\end{ספרור}
שלושת הסוגים הראשונים הם אלו הזוכים בדרך כלל להבלטה ויזואלית ייחודית. אף בספר
זה נשתמש ב\מוסכמות ויזואליות להבלטת המרכיבים הדקדוקיים היסודיים. \עע תכנית
שלום:סי מציגה שוב את התכנית \קד{hello.c} שכתבתי תוך שימוש ב\מוסכמות אלו.
\begin{תכנית}
\setLTR
\lstinputlisting[language=C++,style=Numbered]{00/hello.c}
\setRTL
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת \סי|
\תגית|תכנית:שלום:סי|
\end{תכנית}
\מוסכמות אלו תשמשנה גם בעבור שפות תכנות אחרות. הנה נכתוב למשל תכנית "שָׁלוֹם,
עוֹלָם!" בשפת פסקל.
\begin{קוד}
\bash[verbose,script]
rm -f hello.p; cat << EOF > hello.p
{hello.p: My very first Pascal program. It does not do
too much---it prints the string "Hello, World!" (followed
by a new line), and then terminates.}
program HelloWorld(output);
begin
WriteLn('Hello, World!')
end.
EOF
\END
\end{קוד}
גם את תכנית זו אהדר, כדי לבדוק שלא שגיתי
\bash[script,stdout,ignoreStderr]
pc hello.p
\END
וכמובן, אריץ את התכנית, בכדי לבדוק שהיא אכן עושה את אשר עליה לעשות.
\bash[script,stdout]
./a.out
\END
כעת, \עע תכנית שלום:פסקל מציגה את תכנית הפסקל שכתבתי תוך שימוש ב\מוסכמות שלנו.
\begin{תכנית}
\setLTR
\lstinputlisting[language=Pascalx,style=Numbered]{00/hello.p}
\setRTL
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת פסקל|
\תגית|תכנית:שלום:פסקל|
\end{תכנית}
כפי שניתן לראות הן ב\עע תכנית שלום:סי והן ב\עע תכנית שלום:פסקל, אנו נוהגים
לכתוב תכניות ב\מונח{גופן ברוחב קבוע}. \מונח[מילה שמורה]{המילים השמורות} בתכנית
מודגשות בכך שהן כתובות בגופן עבה מעט יותר, המילולונים מסוג סדריות כתובות בגופן
שבו האותיות נטויות, וה\הערות מופיעות בכתב מסולסל וב\מונח{גופן יחסי}.
בעיון ב\עע תכנית שלום:סי אנו יכולים לזהות שלוש \מונח[מילה שמורה]{מילים שמורות}
בשפת \סי: \מש{int}, \מש{char} וְ-\מש{return}.
לעומת זאת, ההוראה
\LR{\cpp{#include}}
אינה מילה שמורה, וכפי שנווכח בהמשך, עד כמה שהדבר מבלבל, שורה 6 כולה אינה כתובה
בעצם בשפת \סי.
בעיון ב\עע תכנית שלום:פסקל אנו יכולים לזהות שלוש \מונח[מילה שמורה]{מילים
שמורות} בשפת פסקל: המילה \מש{program} המציינת את תחילת התכנית, המילה
\מש{begin} המציינת את תחילת ה\פקודות לביצוע, והמילה \מש{end} המציינת את סוף
רשימת ה\פקודות לביצוע.
קל גם לזהות את המרכיבים הדקדוקיים היסודיים האחרים בשתי התכניות שהצגנו. בשפת
\סי אנו רואים הערה אחת (המשתרעת על שורות 1-4 ב\עע תכנית שלום:סי), שני \מזהים
(המילה \קד{main} והמילה \קד{printf}), את המילולון מסוג \סדרית (בשורה 10), את
ה\מילולון מסוג מספר שלם (המספר \קד{0} בשורה 11) וכן שמונה סימני פיסוק שונים:
\begin{english}
\let\ttfamily=\listingsfont
\begin{CPP}
() { } [ ] ; *
\end{CPP}
\end{english}
ב\עע תכנית שלום:פסקל אנו רואים הערה אחת (בשורה 1), שלושה \מזהים (המילים
\קד{HelloWorld}, \קד{output} וְ-\קד{WriteLn}) ואת ארבעת סימני הפיסוק הבאים:
§ אוצר המילים
בהסבר לעיל של תָּכְנָן של שתי תכניות "שָׁלוֹם, עוֹלָם!" שכתבתי, השתמשתי במונחים
\מונח[מילה שמורה]{מילים שמורות} ו\מזהים. המונחים הללו מוכרים
ודאי לכל מי שכתב תכנית מחשב,
ובכל זאת, כדאי להזכיר את משמעותם, ולדון באופן שבו מוגדר אוצר המילים של שפת
התכנות. אחר כך, נבחין בין סוגי ה\מזהים השונים, ובהם
\מונח[מזהה שמור]{מזהים שמורים},
\מונח[מזהים מוגדרים מראש]{מזהים המוגדרים מראש}, \מונח{מזהי ספריה}, ו\מזהים סתם.
§§ הצורך במזהים
כידוע, תכנית מחשב מתארת תהליך חישובי, והתיאור נעשה כמעט תמיד באורח מודולארי.
שפת התכנות מציעה למשתמש בה אוסף של פעולות חישוביות יסודיות, פעולות הבנויות
בשפה. המתכנת מגדיר סדרות של פעולות חישוביות כאלו, מעניק להן שמות, ומשתמש
בשמות הללו כדי לבנות סדרות מורכבות יותר המכילות אותן.
כך למשל בשפת \סי, המתכנת מגדיר פונקציות, נותן לפונקציות הללו שמות, ואחר כך
משתמש בשמות אשר ניתנו לפונקציות, כדי לפנות אליהן מפונקציות אחרות, ובכך להגדיר
פונקציות מורכבות יותר.
לא רק לפונקציות יש שמות. ניתן לתת שמות ל\משתנים, ל\קבועים,
ל\טיפוסים, ול\ישויות
אחרות המופיעות בתכנית. שם של \ישות כזו נקרא \מזהה.
ו\מזהה כשמו כן הוא: הוא \מזהה \ישות ומאפשר לפנות אליה אחרי
שנוצרה.
§§ הגדרת מזהה חוקי
הדקדוק של שפת התכנות מכיל כללים המגדירים מהו \מזהה חוקי.
כך למשל, בשפת \סי, \מזהה הוא:
\begin{מובאה}
סדרה של תוים היכולים להיות אות לטינית גדולה, \קד{A-Z},
אות לטינית קטנה \קד{a-z}, ספרה \קד{0-9} או
\מונח[תו קו תחתון]{תו הקו התחתון}
\קד{\_},
ובלבד שסדרה זו אינה מתחילה בספרה.
\end{מובאה}
המילים \קד{main} וְ-\קד{printf} שראינו ב\עע תכנית שלום:סי, עומדות בכללים אלו,
ועל כן בקהל ה\מזהים הן תחשבנה.
הכללים הקובעים אם סדרת תוים היא \מזהה אם לאו דומים מאוד בכל השפות,
ובדרך כלל, ניתן להניח כי הגדרת שם מזהה בשפה לא מוכרת היא כמו זו של שפת \סי.
כרגיל, ישנם יוצאים מן הכלל, העשויים אפילו להרגיז: בשפת המקרו של
\LR{\TeX}.
מזהה יכול להכיל אותיות בלבד, ובגירסאות מוקדמות של שפת בייסיק, מזהה יכול היה
להיות בן אות אחת בלבד, או אות בודדת אחריה מופיעה ספרה אחת.%
\הערת␣שוליים{מגבלות
קיצוניות על אורך מזהה היו נפוצות בעבר: בגירסאות מוקדמות של שפת פורטרן, אורכו של
מזהה הוגבל לשישה תוים בלבד, ובגירסאות מוקדמות של שפת \סי, אורך מזהה הוגבל
לשמונה תוים. מגבלות כאלו כמעט שאינן קיימות בשפות חדשות או בגרסאות עדכניות של
שפות ותיקות.}
לבד מחריגים אלו, יש כמה הבדלים עקרוניים בין שפות התכנות, אליהם כדאי לשים לב.
§§ אבחנה בין אותיות גדולות וקטנות
ראשית, ישנן שפות אשר אינן מבחינות בין אותיות גדולות וקטנות, בשפות אלו, אין כל
הבחנה בין המזהים \קד{HELLO}, \קד{Hello}, וְ-\קד{hello}. הסיבה לתכנון כזה של
השפה, יכולה להיות היסטורית (שפת פסקל פותחה על מחשבים שבהם אוסף התוים לא הבדיל
בין אותיות גדולות וקטנות), או עקרונית, אם לדעת מתכנן השפה, האבחנה בין אותיות
קטנות וגדולות, הינה מבלבלת או מיותרת.
בשפות רבות, ישנן \מוסכמות ביחס לשימוש באותיות גדולות וקטנות בעבור \מזהים מסוגים
שונים. בשפת \גאוה למשל, מקובל לכנות \מחלקה בשם המתחיל באות גדולה, לתת ל\קבועים
שמות המורכבים מאותיות גדולות בלבד, ולהשתמש בשם המתחיל באות קטנה בעבור
כל ה\ישויות האחרות, כולל פונקציות ו\משתנים.
ה\מהדר אינו אוכף את ה\מוסכמות הללו, ותכנית שאינה מצייתת
ל\מוסכמות, היא עדיין תכנית חוקית. בכל זאת, יש חשיבות ל\מוסכמות
הללו, בכך שהן מקלות על כתיבת התכנית: כאשר כתבתי את
\עע תכנית שלום:גאוה, לא הייתי צריך להתלבט אם לכנות את
ה\מחלקה \קד{HELLO}, או \קד{hello}. פעלתי באורח מוכני
לפי ה\מוסכמות, והשתמשתי ב\מזהה{Hello} ל\מחלקה.
שימוש ב\מוסכמות מקל גם על הקורא. כאשר בתכנית \גאוה מופיעה
ה\פקודה
\begin{קוד}
\begin{Pascal}
foo.bar();
\end{Pascal}
\end{קוד}
קל לנחש כי המזהה \קד{foo} מתייחס ל\משתנה, אשר עליו מופעלת הפונקציה
\שי{\קד{bar()}}. לעומת זאת, הכתיב
\begin{קוד}
\begin{Pascal}
Foo.bar();
\end{Pascal}
\end{קוד}
רומז כי מדובר ב\מחלקה אשר שמה הוא \קד{Foo}, וכי המזהה \קד{bar}
מתייחס לפונקציה \סטאטית המוגדרת בתוכה.
צריך לשים לב כי ה\מוסכמות הללו עשויות להשתנו בין שפה לשפה.
בשפת אייפל למשל, מקובל כי ה\מזהה של מחלקה נכתב כולו באותיות
גדולות, ובשפת \שי{\CSharp} מקובל דווקא לתת לפונקציות שמות המתחילים באות גדולה.
§§ הגבלת מזהים לישויות מסוג מסויים
בשפות מסויימות, המבנה הדקדוקי של ה\מזהה קובע בעבור מה ניתן להשתמש בו. בשפת
פרולוג לדוגמא, שם של \משתנה חייב להתחיל באות גדולה או ב\מונח[תו קו תחתון]{תו
הקו התחתון}.
בשפות אחרות, המבנה הדקדוקי של ה\מזהה עשוי לקבוע את טיבו של הפריט המזוהה. כך
למשל בשפת פורטרן, טיפוסו של \משתנה אשר שמו מתחיל באות-I הוא מספר שלם, ואילו
הטיפוס של \משתנה אשר שמו מתחיל באות-X הוא מספר ממשי.
הכתבה דומה קיימת גם בשפת פרל, שם \מזהה המתחיל בסימן \קד{\$} יכול להתייחס רק
למשתנה סקלארי, \מזהה המתחיל בסימן \קד{\@} יכול להתייחס רק למערך, \מזהה המתחיל
בתו \קד{%} יכול להתייחס רק לטבלת ערבול, ואילו \מזהה המתחיל באות מאותיות
האלפבית הלטיני, יכול להתייחס אך ורק לפונקציה.
§§ מזהה הבנוי מהלחם של כמה מילים
תכנון שפת תכנות מנסה לתת מענה גם לצורך של מתכנתים לתת לישויות שמות אשר יבטאו
את תָּכְנָן. זו הסיבה ששפות מודרניות נִתְּצוּ את שלשלאות ה-ASCII והן מתירות שימוש
בתוי יוניקוד. מזהים בשפות כאלו יכולים להכיל אותיות הלקוחות מכל אלפבית שהוא.
בתכנות של אלגוריתם מתימטי, השם~$Γ$ הוא שם סביר ביותר לפונקציה.
קושי מהותי יותר במתן שמות משמעותיים
הוא העובדה שלעיתים נדרשת יותר מאשר מילה אחת
כדי לבטא נכונה את מהותה של ישות. אמנם \מזהים כמו \קד{fileopen}
הם לגיטימיים, אך בכל זאת, קל הרבה יותר לזהות את שתי המילים שהולחמו לכדי \מזהה
אחד אם שמו יהיה \קד{file\_open}.
אכן, מקובל להשתמש בקו התחתון להפריד בין שתי מילים מולחמות, וזו כנראה אחת
הסיבות החשובות שניתן היתר להשתמש בתו הקו התחתון במזהים. \מוסכמה מקובלת אחרת
היא להשתמש במה שקוראים \הדגש{camelCase} כדי להפריד ויזואלית בין מילים מולחמות.
לפי \מוסכמה זו, כל מילה מולחמת, לבד מהמילה הראשונה, תתחיל באות גדולה. כך,
נכתוב \קד{fileOpen} כדי לציין את ה\מזהה שמורכב מהלחם של המילה {file} עם המילה
\שי{open}.
כזכור, שפת פסקל אינה מבחינה בין אותיות גדולות וקטנות. כאשר כתבתי
\מוגדרת␣מראש{WriteLn} בשורה מס'~7 ב\עע תכנית שלום:פסקל, השתמשתי ב\מוסכמה הידועה
בשם \הדגש{PascalCase} כדי להפריד בין המילה {write} ובין המילה \שי{ln} (שהיא
קיצור למילה \שי{line}), כדי להציג את ה\מזהה הזה. ב-{PascalCase} כל המילים
המולחמות מתחילות באות גדולה. (שים לב לכך שכיוון שפסקל אינה מבחינה בין אותיות
גדולות וקטנות יכולתי לכתוב \מוגדרת␣מראש{writeln} או \מוגדרת␣מראש{WRITELN} מבלי
לשנות מהתכנית כלל.)
בשפת קובול, תו המקף (\קד{-}), המשמש בדרך כלל לציון פעולת החיסור יכול להופיע
במזהה. ב\עע תכנית שלום:קובול ("שָׁלוֹם, עוֹלָם!" בשפת קובול), אנו רואים מספר לא קטן
של \מזהים המכילים בתוכם מקף.
\begin{תכנית}
\setLTR
\lstset{comment=[f][commentstyle][1]*}
\begin{COBOL}
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
*** Hello, World! in the COBOL programming language
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. RM-COBOL.
OBJECT-COMPUTER. RM-COBOL.
DATA DIVISION.
FILE SECTION.
PROCEDURE DIVISION.
MAIN-LOGIC SECTION.
BEGIN.
DISPLAY " " LINE 1 POSITION 1 ERASE EOS.
DISPLAY 'Hello, World!' LINE 15 POSITION 10.
STOP RUN.
MAIN-LOGIC-EXIT.
EXIT.
\end{COBOL}
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת קובול|
\תגית|תכנית:שלום:קובול|
\end{תכנית}
שפת אלגול 68, כמו גם שפת פורטרן מתעלמת מרווחים המופיעים בתוך \מזהים, דבר המאפשר
להפריד בין מילים מולחמות באמצעות רווחים.
§ מילים שמורות וסוגי מזהים
\מונח[מילה שמורה]{המילים השמורות} הינן מילים אשר למרות שהן עומדות בכללים
הקובעים מהו \מזהה, הן שמורות למטרות אחרות, ולא ניתן להשתמש בהן לשם מתן שם
ל\ישויות אשר נוצרו על ידי המתכנת. כך למשל המילה \מש{int} בשפת \סי עומדת בכללים
המגדירים \מזהה חוקי בשפה, אך היא אינה \מזהה. לא ניתן לכתוב פונקציה בשפת \סי
אשר שמה הוא \מש{int}.
§§ קבוצות מוגדרות רקורסיבית
לאילו צרכים משמשות אם כן \מונח[מילה שמורה]{המילים השמורות}? במקרים
רבים, \מונח[מילה שמורה]{המילים השמורות} משמשות כעין סימני פיסוק. המילים
\מש{program}, \מש{begin} וְ-\מש{end} בשפת פסקל הן בבירור כאלו. יש עוד שימושים
רבים אחרים למילים השמורות, ואין זה המקום למנות את כל אלו. כאן אנו נתמקד בשימוש
אחד חשוב של \מונח[מילה שמורה]{מילים שמורות}. לעיתים, \מונח[מילה שמורה]{מילים
שמורות} משמשות לזיהוי \ישויות "אטומיות". כדי להבין את המונח \ישות אטומית,
נזדקק להגדרה הבאה:
נאמר על קבוצה כי היא \מונח[קבוצה מוגדרת רקורסיבית]{מוגדרת רקורסיבית}
אם הגדרת הקבוצה בנויה על פי התבנית הבאה:
\begin{ספרור}
✦ רשימה, בדרך כלל סופית וקצרה של ערכים יסודיים.
✦ מנגנון או מנגנונים לבניה של ערכים מורכבים מהערכים היסודיים
וערכים מורכבים אחרים.
\end{ספרור}
כך לדוגמא, קבוצת ה\ביטויים היכולים להפיע בשפת תכנות כגון שפת פסקל, היא קבוצה
המוגדרת רקורסיבית: ה\ביטויים היסודיים הם מילולונים וקריאת ערכם של \משתנים.
ביטויים מורכבים נוצרים מביטויים אחרים, היכולים להיות ביטויים יסודיים, או
ביטויים מורכבים אחרים, באמצעות מגוון של פעולות, הכוללות, בין השאר, את פעולות
החשבון וקריאות לפונקציה.
\ישות מקבוצה המוגדרת רקורסיבית היא \ישות אטומית אם לא ניתן לזהות בתוכה
תת-\ישות השייכת לאותה קבוצה. חשוב להבין כי \ישות אטומית אינה בהכרח לא פריקה,
כל שנדרש הוא שלא ניתן לזהות בתוכה תת-\ישות מאותה קבוצה. הנה, קבוצת הפקודות
במרבית שפת תכנות היא קבוצה המוגדרת רקורסיבית, ובתוך קבוצה זו, אנו יכולים לזהות
את הפקודות האטומיות. בשפת פסקל, \הצבה היא \פקודה אטומית. אבל, אם נעיין ב\פקודה
\begin{קוד}
\pascal{a :=b+c;}
\end{קוד}
שהיא \פקודה אטומית, נוכל לזהות בה תתי מרכיבים, למשל הביטוי \קד{b+c}. בכל זאת,
הפקודה לעיל היא פקודה פרימטיבית, שכן לא ניתן לזהות בה תת-מרכיב שהוא
\פקודה בעצמו.
לעומת זאת, ה\פקודה הבאה בפסקל,
\begin{קוד}
\begin{PASCAL}
begin
a :=b+c;
end
\end{PASCAL}
\end{קוד}
אינה פקודה אטומית, שכן ניתן לאתר בה מרכיב שהוא \פקודה בעצמו.
קבוצת ה\טיפוסים של שפת \סי (כמו גם קבוצת הטיפוסים של שפת פסקל) אף היא קבוצה
המוגדרת רקורסיבית: ישנם טיפוסים מורכבים, אשר ניתן לזהות כי הם מורכבים מיחידות
קטנות יותר, אשר אף הן טיפוסים. בטיפוס רשומה למשל ניתן לזהות כיחידות
קטנות יותר את טיפוסי השדות הבונים את הרשומה. אנו אומרים שהטיפוס של רשומה
הוא \מונח{טיפוס מורכב}, משום שיש בו תתי-יחידות אשר אף הן טיפוסים.
לעומת ה\מונח[טיפוס מורכב]{טיפוסים המורכבים}, ישנם טיפוסים אטומיים, כלומר
טיפוסים אשר לא ניתן לזהות בתוכם טיפוסים אחרים. הטיפוס של מספרים שלמים או
הטיפוס של מספרים ממשיים, הם דוגמאות לטיפוסים כאלו.
המילה השמורה \מש{int} בשפת \סי \מזהה את הטיפוס האטומי של מספר שלם.
מילים
שמורות המשמשות כ\מזהים נקראות \מונח{מזהה שמור}.
שפת פסקל נוקטת בשיטה אחרת במקצת לזיהוי הטיפוסים האטומיים. המילה
\מוגדרת␣מראש{Integer} אשר מתארת את הטיפוס האטומי של מספרים שלמים בשפת
פסקל אינה מילה שמורה. אלא היא מילה \הדגש{מוגדרת מראש}. המונח מילה מוגדרת
מראש, מכוונת לכך שאף בתכנית פסקל ריקה, קיימת הגדרה הקושרת את
ה\מזהה{} \מוגדרת␣מראש{WriteLn} אל הטיפוס האטומי של מספרים שלמים. עלינו להבחין בין
הטיפוס, ובין שמו: אין למתכנת גישה לטיפוס האטומי הזה עצמו---אין באפשרותו לבחון
אותו, או לנסות לפרק אותו למרכיבים. אלא, שבניגוד למילים שמורות, ישנה האפשרות
למתכנת להשתמש בשמו של הטיפוס \מוגדרת␣מראש{Integer} מחדש לצרכים אחרים לפי
בחירתו, כלומר לקשור את ה\מזהה הזה לשפה אחרת.
גם קבוצת הפעולות החישוביות היא קבוצה המוגדרת רקורסיבית. ישנן פעולות חישוביות
אטומיות של שפת התכנות, כאלו שאי אפשר לחלק אותן לתתי-יחידות שאף הן פעולות
חישוביות, וכנגדן ישנן הפעולות החישוביות המורכבות, כגון פונקציה בשפת \סי.
מקצת הפעולות החישוביות האטומיות בשפת \סי ופסקל מסומנות בסימני פעולה, הכוללים
בין היתר אופרטורים מתימטיים שונים. ישנן גם פעולות חישוביות אטומיות אשר להן
הוקדשה מילה שמורה. ה\פקודה
\begin{קוד}
\cpp{return 0;}
\end{קוד}
אשר בשורה 11 ב\עע תכנית שלום:סי, עושה שימוש במילה שמורה כזו.
ישנן שפות, כמו קובול, המקד\ישות מספר רב של \מונח[מילה שמורה]{מילים שמורות}
לפעולות החישוביות האטומיות. בין השאר, יש בקובול \מונח[מילה שמורה]{מילים
שמורות} יחודיות בעבור חיבור, חיסור, כפל וחילוק.
§§ מזהים שמורים לשגרות
על אף העובדה שקבוצת הפעולות החישוביות מוגדרת רקורסיבית, אין די בחלוקה לפעולות
מורכבות ולפעולות אטומיות. ישנן פעולות חישוביות רבות אשר על אף שאינן אטומיות,
מתכנת רגיל לא ירצה לבנותן בעצמו. הדוגמא הראשית לסוג כזה של פעולות הן פעולות של
הוצאת פלט וקבלת קלט.
ישנן שפות בהן פעולות של קלט ופלט בנויות לתוך השפה, והגישה אליהן נעשית באמצעות
\מזהים שמורים. כזהו המצב בשפת \AWK, כמודגם ב\עע תכנית שלום:AWK.
\bash
cat << EOF > hello.awk
#!/usr/bin/gawk -f
BEGIN { # "Hello, World!" in the AWK programming language
print("Hello, World!")
exit
}
EOF
chmod +x hello.awk
./hello.awk
\END
\begin{תכנית}
\setLTR
\lstinputlisting[language=AWK,style=Numbered]{00/hello.awk}
\setRTL
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת AWK|
\תגית|תכנית:שלום:AWK|
\end{תכנית}
המילה \מש{print} המופיעה בשורה מס'~8 בתכנית היא מילה שמורה. כלומר, נאסר על
המתכנת להשתמש בשם זה בעבור \ישויות אחרות בתכנית, והגדרת משמעותה של הפונקציה
\מש{print} היא חלק מהגדרת שפת \שי{AWK}.
§§ מזהים מוגדרים מראש
האופן שבו מאפשרת שפת פסקל שימוש בפעולות של קלט ופלט היא מעט שונה מזו הנוהגת
בשפת \שי{AWK}. במקום \מונח[מילה שמורה]{מילים שמורות}, שמן של פעולות הקלט והפלט
הוא \מזהים המוגדרים מראש. ה\שגרה \מוגדרת␣מראש{WriteLn} אשר נקראה בשורה 4 של
\עע תכנית שלום:פסקל, היא בדיוק כזו. זוהי \שגרה הבנויה בשפת התכנות פסקל, ואשר
למתכנת אין גישה אליה. כלומר, המתכנת אינו יכול לבחון את אופן המימוש של ה\שגרה,
והוא אף אינו יכול לממש מחדש באופן אחר את ה\שגרה הזו. יתירה מזאת, משמעותה של
ה\שגרה היא חלק בלתי נפרד מהגדרת שפת פסקל.
בכל זאת, המילה \מוגדרת␣מראש{WriteLn} אינה \מונח{מילה שמורה}. המילה אמנם \מזהה
\שגרה הבנויה בשפה, אך הרשות מסורה בידי המתכנת לקשור שם זה ל\ישות אחרת.
ב\עע תכנית שלום:פסקל נצבעו המזהים המוגדרים מראש בצבע כחול. אנו רואים שגם המילה
\מוגדרת␣מראש{output} צבועה בצבע זה. מילה זו אף היא מהווה \מזהה מוגדר מראש, אך
אנו לא נעמיק בו.
כיצד מוממשה ה\שגרה{} \מוגדרת␣מראש{WriteLn} בפסקל? כיצד מומשה הפונקציה
\קד{printf} בשפת \סי? מסתבר כי על אף שמדובר בפעולות חישוביות מורכבות, אי אפשר
לממש אותן רק באמצעות הפעולות החישוביות האטומיות שבשפה. שפת פסקל אינה מגלה
למשתמש בה כיצד נסגר הפער הזה. לעומת זאת, ההגדרה של שפת \סי, מכילה "דלת אחורית"
שבאמצעותה אפשר לממש את \קד{printf}. מהותה של דלת אחורית זו היא הן היכולת להפעיל
מתוך שפת \סי \פקודות חישוביות בשפת מכונה, והן היכולת לקרוא משפת \סי ישירות
לשירותים של מערכת ההפעלה. הגדרתה של שפת פסקל אינה חושפת בפני
המשתמש דלת אחורית כזו---כל הפעולות אותן יכול המתכנת לעשות בשפת פסקל
מוגדרות כחלק מהגדרת השפה עצמה. אך כמובן, המימוש של \מוגדרת␣מראש{WriteLn} (אשר אינו
חשוף למשתמש בשפה) חייב להשתמש במנגנונים המצויים מחוץ לשפה עצמה.
האופן שבו שפת \סי תומכת בפעולות קלט ופלט שונה מהותית מזו של שפת פסקל. הפונקציה
\קד{printf} אשר נקראה בשורה 11 של \עע תכנית שלום:סי, הוגדרה בספריה. הספריה היא
אמנם סטנדרטית, במובן זה שבדרך כלל כל תכנית \סי שתכתוב תוכל לקרוא לה. אולם,
הספריה ניתנת להחלפה, והרשות נתונה בידי המתכנת לממש אותה מחדש.
§§ סיכום: סוגי מזהים
\עע טבלא מזהים מסכמת את ההבדלים בין הסוגים השונים של המזהים: \מזהים שמורים הם
התקיפים ביותר: הם זמינים תמיד, לא ניתן למתכנת לבחון את מימושם, נאסר עליו לשנות
את המימוש, ונאסר עליו להשתמש במזהים אלו לצורך אחר. חלשים מעט מאלו הם המזהים
המוגדרים מראש, אשר הותר למתכנת לקשור אותם למימוש אחר. מזהי ספריה הם החלשים
ביותר: אמנם הם זמינים תמיד, אך המתכנת יכול לבחון את המימוש שלהם ולשנותו, וכן
להשתמש בהם לצרכים אחרים.
\begin{טבלא}[!htbp]
\begin{center}
\renewcommand\codesize\footnotesize
\footnotesize
\begin{tabular}{|r||r|p{16ex}|p{16ex}|p{16ex}|}
\hline
סוג & דוגמא & שם מוגן מפני שימושים נוספים
& מימוש חשוף למתכנת ובר שינוי על ידו
& מובנה בסביבת העבודה
⏎ \hline
\מזהה שמור & \מש{print} בשפת AWK & כן & לא & כן ⏎
\מזהה מוגדר מראש &
\begingroup\color{blue}\קד{WriteLn}\endgroup{}
בשפת פסקל & לא & לא & כן ⏎
\מזהה ספריה & \קד{printf} בשפת \סי & לא & כן & כן ⏎
\מזהה אחר & \קד{HelloWorld} ב\עע תכנית שלום:פסקל & לא & כן & לא ⏎
\hline
\end{tabular}
\end{center}
\כיתוב|סוגי מזהים בשפות תכנות|
\תגית|טבלא:מזהים|
\end{טבלא}
הנטיה המודרנית היא להשתמש ככל שניתן במזהי ספריה בעבור פעולות קלט פלט
ודומותיהן, ולמעט בשימוש במזהים מוגדרים מראש ובמזהים שמורים. הסיבה היא שמימוש
העשוי במסגרת השפה מסבך את הגדרת השפה שלא לצורך וכובל אותה מפני שינויים בעתיד.
בשפת \סי למשל, אין \מזהים מוגדרים מראש כלל.
הנטיה המודרנית התרחקה גם מהגישה של שפת פסקל להגדיר טיפוסים אטומיים באמצעות
\מזהים מוגדרים מראש, אולם מפאת הקושי להגדיר טיפוסים אטומיים באמצעות ספריה, אף
אם לזו יש גישה לשפת מכונה, בשפות מודרניות טיפוסים אטומיים מוצעים למתכנת בדרך
כלל באמצעות \מזהים שמורים.
הבה ונבחן את \עע תכנית שלום:Go, תכנית "שָׁלוֹם, עוֹלָם!" בשפת \Go, באמצעות המונחים
שהכרנו.
\begin{תכנית}
\begin{GOn}
// "Hello, World!" in the Go programming language
package main
import "fmt"
func main() {
fmt.Printf("Hello, World!\n")
}
\end{GOn}
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת Go|
\תגית|תכנית:שלום:Go|
\end{תכנית}
אף מבלי להכיר את שפת \שי{Go}, קל להסיק שהמילים השמורות שבשפה אשר מופיעות
בתכנית, \מש{package}, \מש{import}, וְ-\מש{func}, אינן בבחינת \מזהים, משום שהן
אינן נוקבות בשמה של \ישות תכנותית.
לעומתן, שם הפונקציה \קד{Printf} אשר אחראית להצגת ה\סדרית, היא \מזהה ספריה.
§ יבוא מזהים מהספריה
אם הספריה הסטנדרטית של שפת התכנות אינה חלק משפת התכנות עצמה, הרי אפשר להחליף
את הספריה הזו בספריה אחרת. כך למשל, אפשר לכתוב ספריה חליפית בעבור שפת \סי בה
הפונקציה המציגה סדריות נקראת למשל \קד{typeoupt}. אם נעשה כן, יהיה צורך כמובן
לכתוב את \עע תכנית שלום:סי מעט אחרת.
בכל שפה המשתמשת במזהי ספריה, נדרשת אם כן דרך להודיע ל\מהדר מהם המזהים המצויים
בספריה. בדיקה בעין בוחנת של התכנית "שָׁלוֹם, עוֹלָם!" בשפה המשתמשת במזהי ספריה תגלה
את האופן שבו הדבר נעשה.
§§ יבוא באמצעות מילה שמורה
ב\עע תכנית שלום:Go הכתובה בשפת \Go היבוא של \מזהים מהספריה נעשה באמצעות ההוראה
\begin{קוד}
\go{import "fmt"}
\end{קוד}
המצוייה בשורה מס'~3, ובה מילה שמורה של השפה אחראית ל\יבוא ה\מזהה.
נשים לב לכך שהפונקציה \קד{Printf} מצוייה בתוך חבילה אשר שמה \קד{fmt} וכי
ההוראה
\begin{קוד}
\go{import "fmt"}
\end{קוד}
מייבאת את החבילה כולה.
נשים לב גם לכך שהקריאה לפונקציה \קד{Printf} מציינת שהיא נלקחת מתוך
החבילה \קד{fmt}, ככתוב בשורה מס'~5 ב\עע תכנית שלום:Go{:}
\begin{קוד}
\lstset{language=Golang}
\lstinline+fmt.Printf("Hello, World!\n")+
\end{קוד}
גם שפת עָדָה משתמשת במזהי ספריה. עיון בתכנית "שָׁלוֹם, עוֹלָם!" הכתובה בשפה זו (\עע
תכנית שלום:עָדָה), מגלה מבנה זהה כמעט לחלוטין לזה של שפת \Go, אם כי המילים הן
אחרות.
\begin{תכנית}
\begin{ADAn}
--Hello, World! in the Ada programming language
with Text_IO;
procedure Hello_World is
begin
Text_IO.Put_Line("Hello, World!");
end Hello_World;
\end{ADAn}
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת עָדָה|
\תגית|תכנית:שלום:עָדָה|
\end{תכנית}
שם פעולת הפלט בשפת עָדָה הוא \קד{Put\_Line}, והיא מצוייה בחבילה אשר שמה הוא
\קד{Text\_IO}. ההוראה
\begin{קוד}
\ada{with Text_IO;}
\end{קוד}
(שורה מס'~2 בתכנית) אף היא משתמשת במילה שמורה של שפת עָדָה בכדי לייבא חבילה זו
לתוך התכנית. זאת, ועוד, אף בשפת עָדָה, ההפעלה של \קד{Text\_IO} מציינת את החבילה
המכילה:
\begin{קוד}
\begin{ADA}
Text_IO.Put_Line("Hello, World!");
\end{ADA}
\end{קוד}
§§ יבוא באמצעות עיבוד מקדים
בשפת \סי היבוא של מזהי הספריה נעשה באופן מעט אחר. ב\עע תכנית שלום:סי הכתובה
בשפת \סי אחראית על כך ההוראה
\begin{קוד}
%\lstinline[language=C++]/#include <stdio.h>/
\end{קוד}
הגיעה העת להסביר מדוע נאמר לעיל שהוראה זו אינה כתובה בשפת \סי. מודל ההידור של
שפת \סי הוא יחודי בכך שההידור מתבצע בשני שלבים: טרם ההידור עצמו, מופעלת על
הקובץ המכיל תכנית \סי תכנית עיבוד ראשוני הידועה בשם \מונח[מעבד מקדים]{המעבד
המקדים}. שורות בקובץ התכנית המתחילות בתו הסולמית \קד{#} הן הנחיות \מונח[מעבד
מקדים]{למעבד המקדים} לביצוע טרנספורמציות טכסטואליות שונות על הקובץ אותו הוא
קורא. רק בשלב שני, מועבר תוצאת הטרנספורמציות הללו כקלט ל\מהדר עצמו לשם ביצוע
ההידור.
%בפרט, ההוראה \lstinline/#include/ מורה \מונח[מעבד מקדים]{למעבד המקדים} להכניס את תכנו
של קובץ אחר לתוך הקובץ המקורי. על כן, ההוראה
\begin{קוד}
%\lstinline/#include <stdio.h>/
\end{קוד}
תוחלף על ידי המעבד המקדים בתוכנו של קובץ אשר שמו \קד{stdio.h}, ואשר אותו יחפש
המעבד המקדים במקומות שונים במערכת הקבצים. תוכנו של קובץ זה מתאר את הפונקציה
\קד{printf} אשר בה משתמשת התכנית.
אמנם הפעלה של ה\מהדר תגרום מאחורי הקלעים להפעלה של \מונח[מעבד מקדים]{המעבד
המקדים}, אך ניתן גם להפעיל את \מונח[מעבד מקדים]{המעבד המקדים} לבדו.
\bash[script,stdout]
cpp -P hello.c > hello.P.c
\END
הבה נשווה את גדלם של שני הקבצים:
\bash[script,stdout]
wc -l hello.c
\END
\bash[script,stdout]
wc -l hello.P.c
\END
אנו רואים שהקובץ לאחר \מונח[עיבוד מקדים]{העיבוד המקדים} גדול בהרבה מהקובץ
המקורי, ולכן לא נציג את כולו כאן. בכל זאת, ניתן לראות שאחרי העיבוד המקדים,
התווספה לתכנית שורה המגדירה את הפונקציה \קד{printf}
\bash[script,stdout]
grep -n "\<printf\>" hello.P.c
\END
ראינו אם כן שתי גישות ליבוא של מזהי הספריה אל התכנית המשתמשת בהן. בשפת \סי
היבוא נעשה באמצעות תהליך של \מונח{עיבוד מקדים} שהינו במובנים רבים בלתי תלוי
בתהליך ההידור עצמו. לעומת זאת, בשפות Go ועדה, היבוא נעשה באמצעות \מונח[מילה
שמורה]{מילים שמורות} של שפת התכנות.
§§ יבוא אוטומטי
לסיום הדיון בשאלת היבוא, נעייין ב\עע תכנית שלום:גאוה, תכנית "שָׁלוֹם, עוֹלָם!"
בשפת \גאוה. מסתבר שאף בשפה זו יש לבצע יבוא של מזהי הספריה, אלא, שבדיקתה של
\עע תכנית שלום:גאוה לא תגלה שם את פקודת היבוא.
\begin{תכנית}
\bash
cat << EOF > Hello.java
// Hello.java: my first Java program. It prints
// the string "Hello, World!" on the standard output
// stream, and then terminates.
class HelloWorld {¢¢
static public void main(String args[]) {¢¢
System.out.println("Hello, World!");
}
}
EOF
\END
\setLTR
\lstinputlisting[language=Java,style=Numbered]{00/Hello.java}
\setRTL
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת \גאוה|
\תגית|תכנית:שלום:גאוה|
\end{תכנית}
מתברר כי הגדרת השפה היא כזו ש\יבוא של חלקים נבחרים מהספריה נעשה באורח אוטומטי
על ידי ה\מהדר. המתכנת אמנם רשאי לכתוב את פקודת ה\יבוא של חלקים אלו בעצמו,
אך אין לו צורך לעשות כן. בין אם יעשה זאת ובין אם לאו, ה\מהדר ייבא את
החלקים האמורים.
§ סביבת העבודה ונקודת התחלת הביצוע
עיקרן של כל תכניות "שָׁלוֹם, עוֹלָם!" שראינו היה הוראה אחת להציג את ה\סדרית הזו.
אנו נקרא להוראה חישובית כזו \פקודה.
בתכניות גדולות יותר, יהיה מספר לא קטן של \פקודות. \פקודות אלו תהיינה מאורגנות
בבלוקים---סדרת \פקודות המיועדת להתבצע כמקשה אחת. בלוקים יכולים להיות מקוננים
זה בזה. ניתן גם לכנות בלוק של \פקודות בשם. בשפת בשפת \סי בלוק של \פקודות בעל
שם נודע בשם פונקציה. בשפת פסקל ישנו סוג נוסף של בלוקים כאלו---\שגרות.
אם יש יותר מהוראה אחת בתכנית, יש צורך לקבוע את סדר ביצוע ההוראות. בתוך כל
קבוצה הסדר מוגדר: בדרך כלל, אחרי ביצוע הוראה מסויימת בקבוצה מסויימת, תבוצע
ההוראה הבאה אחריה. כך למשל ב\עע תכנית שלום:AWK אחרי שה\מפרש של AWK יבצע את
ההוראה
\begin{קוד}
\begin{CPP}
print("Hello, World!")
\end{CPP}
\end{קוד}
(שורה מס'~8 ב\עע תכנית שלום:AWK) הוא יבצע את ההוראה העוקבת \שי{\awk{exit}}
(שורה מס~9).
גם הסדר היחסי של הביצוע של הקבוצות ברור בדרך כלל. ביצוע של קבוצה מסויימת יכול
להעצר זמנית כאשר מתבצעת \פקודה המעבירה את חוט הביצוע לקבוצה אחרת, ולהימשך כאשר
הקבוצה האחרת סיימה.
אולם, כאשר יש מספר קבוצות של \פקודות בתכנית, יש צורך לקבוע מי מהן תתבצע
ראשונה. מבט עין בוחנת בתכנית "שָׁלוֹם, עוֹלָם!" צריך לגלות מהו המנגנון אותו מספקת
שפת התכנות לקביעת נקודת ההתחלה, וכיצד השתמשה התכנית במנגנון זה.
ענין קשור הוא זה של התווית גבולות התכנית: כלומר, קביעה מדוייקת
של הקוד הכלול בתכנית והקוד אשר אינו כלול בה. כאשר נאמר למעלה כי המימוש של
הפונקציה \קד{printf} נמצא במה שקראנו ה"ספריה הסטנדרטית", הרי התווית גבולות
התכנית כוללת בתוכה קביעה של מה בדיוק כלול ב"ספריה הסטנדרטית" הזו.
התווית גבולות התכנית מתייחסת גם לתנאים שבו התכנית משתרעת על פני יותר מאשר
קובץ אחד. מתברר כי ככל שהתכנית גדלה, גדל גם הצורך לחלק את תכנה על פני מספר
קבצים, וכמובן, כאשר תכנית נכתבת על ידי יותר מאדם אחד, חלוקתה למספר קבצים היא
חיונית. התוויית גבולות התכנית משמעה גם קביעה אלו מבין הקבצים כלולים בתכנית,
ואלו מצויים מחוץ לה.
במרבית שפות התכנות, האופן שבו מותווים הגבולות אינו גלוי מידית לעין, ונדרשת
הבנה של תהליך ההידור וההרצה בכדי להכיר את פרטיו. בכל זאת, כדי לכתוב תכניות
קטנות, אין צורך בהכרת התהליך לעומקו. כך למשל, כאשר כתבתי למעלה,
\begin{קוד}
\bash[script,stdout]
cc hello.c
\END
\end{קוד}
הפעיל ה\מהדר של שפת \סי את \מונח[מעבד מקדים]{המעבד המקדים}, אשר מצא בעבורי את הקובץ
\קד{stdio.h}, ואחר כך הודרה התכנית, תוך שה\מהדר מוסיף לה את החלקים הנדרשים
מהספריה הסטנדרטית כדי שהתכנית תוכל לפעול.
ניתן להבחין בשלוש גישות עיקריות לקביעת נקודת תחילת הביצוע. גישות אלו קשורות
גם לאופן שבו נקבעים גבולות התכנית.
§§ הגישה האוטרקית
על פי הגישה האוטרקית הנהוגה בשפות תכנות מסויימות, אחת \מונח[מילה שמורה]{המילים
השמורות} קובעת את קבוצת ה\פקודות שתבוצע ראשונה. כך, בפסקל (\עע תכנית
שלום:פסקל), מציינת המילה השמורה \מש{program} שיכולה להופיע רק פעם אחת בתכנית,
את נקודת התחלת הביצוע. נשים לב לכך שלשם התכנית עצמה, \קד{HelloWorld}, שהוא
\מזהה המוגדר על ידי המשתמש, לא נודעת כל חשיבות.
גם ב-AWK המצב דומה. מילה שמורה יעודית, \מש{BEGIN}, קובעת את נקודת התחלת
הביצוע (אך בניגוד לפסקל, אין ב-AWK צורך לתת שם לתכנית).
למעשה, ניתן להגדיר בלוקים של \פקודות המתוייגים במילה זו, וכל אחד מהם
יבוצע ב"תחילת" התכנית. סדר הביצוע של הבלוקים המסומנים ב-\מש{BEGIN}
יהיה על פי סדר הופעתם בתכנית.
גם שפת פסקל וגם שפת AWK מתאפיינות בשתי תכונות חשובות: ראשית, התכנית כולה נכתבת
בקובץ אחד ויחיד, ושנית, בשפות אלו אין מה שכינינו ספריה סטנדרטית: \שגרות העזר
כולן מוגדרות כחלק משפת התכנות עצמה. (כזכור, שתי השפות נבדלות בכך ששמות ה\שגרות
ב-AWK הם \מזהים שמורים, ואילו בפסקל, שמות \שגרות העזר הן מילים מוגדרות מראש.)
בשתי השפות האלו על כן התוויית גבולות התכנית היא פשוטה: אין בתכנית דבר מלבד
הכתוב בקובץ היחיד שבו היא מצויה, וכל האמור בקובץ זה הוא חלק מהתכנית.
§§ הגישה המטאפיסית
הגישה השניה לקביעת נקודת ההתחלה היא נפוצה הרבה יותר: על פי גישה זו, הביצוע
מתחיל מפונקציה בעלת שם מסויים, אלא ששם הפונקציה הזו אינו מילה שמורה. יתירה
מכך, הגדרת נקודת ההתחלה הזו אינה חלק מהגדרת שפת התכנות עצמה.
גישה זו מיוצגת על ידי שפת \סי למשל, שבה אין מילה שמורה בעלת תפקיד דומה למילה
\מש{program} שבשפת פסקל. במרבית המקרים שפת \סי מתחילות את הביצוע בפונקציה אשר
שמה הוא \קד{main}, ובאמת, ב\עע תכנית שלום:סי, הקריאה ל-\קד{printf} היא ה\פקודה
הראשונה ב-\קד{main}.
אולם, העובדה שהתכנית מתחילה דווקא בפונקציה \קד{main} מוכתבת על ידי המימוש של
ה\מהדר, והאופן בו הופעל ה\מהדר.
\עע תכנית שלום:חלונות מציגה תכנית "שָׁלוֹם, עוֹלָם!" בשפת \סי בעבור סביבת חלונות
של חברת מיקרוסופט. אנו רואים שבסביבה זו שם הפונקציה ממנה מתחיל הביצוע הוא
\קד{WinMain}.
\bash
sed -n /begin/,/end/p < hello.p > hello-body.p
\END
\begin{תכנית}
\begin{CPPn}
/* Hello, World! in C for MS-Windows */
#include <windows.h>
int PASCAL WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR CmdLine, int Show)
{¢¢
MessageBox(
GetActiveWindow(),
"Hello, World!",
"Hello Windows World",
MB_OK);
return 0;
}
\end{CPPn}
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת \סי בסביבת חלונות של חברת מיקרוסופט|
\תגית|תכנית:שלום:חלונות|
\end{תכנית}
כזכור, כאשר כתבתי
\bash[script,stdout]
cc hello.c
\END
הוסיף ה\מהדר חלקי קוד לתכנית, ובכך התווה את גבולותיה. חלקים אלו כוללים לא
רק את מימושה של הפונקציה \קד{printf}, אלא גם קטע קוד ראשוני, אשר מופעל טרם
תחילת ביצוע התכנית עצמה. קטע קוד זה אחראי להכנת הארגומנטים לפונקציה \קד{main}
ולהפעלתה.
ניתן בפקודת ההפעלה של ה\מהדר להגדיר את גבולות התכנית באופן אחר, ובפרט לציין
שלא יעשה שימוש בספריה הסטנדרטית או שיעשה שימוש במימוש חילופי לספריה זו, לצרף
\ספריות נוספות וכן קבצים נוספים. כמובן, האופן שבו נעשה הדבר תלוי ב\מהדר, ואינו
חלק מהגדרת שפת התכנות.
§§ הגישה ההוליסטית
הגישה השלישית לקביעת נקודת ההתחלה מכלילה את זו של שפת \סי. על פי גישה זו,
הקביעה מהי נקודת ההתחלה היא עדיין חיצונית לתכנית עצמה, אלא ששפת התכנות משלימה
עם עובדה זו, והגדרת שפת התכנות כוללת בתוכה קביעות מדוייקות ביחס לאופן שבו מתווה
המתכנת את גבולותיה של התכנית, ובכלל זה את נקודת התחלת הביצוע.
בניגוד לגישה המטאפיסית, הגישה ההוליסטית אינה מותירה את הגדרת נקודת התחלת הביצוע
ואת ענין התוויית גבולות התכנית לסביבת הפיתוח. שפת תכנות הנוקטת בגישה ההוליסטית,
לא תתיר קיומן של שתי סביבות עבודה שבהן ענינים אלו יקבעו בדרך שונה.
כאלו הם פני הדברים בשפת אייפל לדוגמא, אשר בה המתכנת כותב קובץ מאגד (Cluster)
אשר מגדיר את סביבת העבודה, ובכלל זה את נקודת התחלת הביצוע. קובץ המאגד הוא אמנם
חיצוני לשפה, אך הוא בכל זאת קשור אליה בקשר הדוק, ובפרט, הדקדוק של קובץ המאגר
דומה מאוד לדקדוק של שפת אייפל עצמה.
הגישה ההוליסטית מופיעה גם בשפות מודרניות אחרות ובכלל אלו שפת \גאוה.
§§ ביצוע אינטראקטיבי
נסתכל כעת ב\עע תכנית שלום:OCaml, המדפיסה "שָׁלוֹם, עוֹלָם!" בשפת \שי{OCaml}.
\begin{תכנית}
\bash
cat << EOF > hello.caml
(* Hello World in OCaml *)
print_string "Hello, World!\n";;
EOF
ocaml hello.caml
\END
\setLTR
\lstset{language=[Objective]Caml,style=Numbered}
\lstinputlisting{00/hello.caml}
\setRTL
\כיתוב|"שָׁלוֹם, עוֹלָם!" בשפת OCaml|
\תגית|תכנית:שלום:OCaml|
\end{תכנית}
בתכנית זו, יש פקודה אחת בלבד.
קל לנחש כי ביצוע התכנית יתחיל מהפקודה הראשונה בקובץ.
אכן, כך הדבר, אך בדיקה תגלה שהתמונה מורכבת מעט יותר, שכן
מודל החישוב הבסיסי ב-OCaml הוא אינטראקטיבי:
לאחר הפעלת תכנית \שי{ocaml}, המתכנת כותב ביטוי, ותכנת ocaml
משערכת ביטוי זה, ומציגה את התוצאה.
תהליך זה מודגם ב\עע איור ocaml.
\begin{איור}[!htbp]
\begin{center}
\includegraphics[width=0.8\textwidth]{Screenshot-hello-caml.jpg}
\end{center}
\כיתוב|שימוש אינטראקטיבי בתכנת ocaml|
\תגית|איור:ocaml|
\end{איור}
כפי שאפשר לראות באיור, האינטראקציה שלי עם תכנת ocaml התחילה כאשר הקלדתי
את המילה \קד{ocaml} אל ה\זרז של תכנת bash.
בתגובה, התעוררה תכנת ocaml והציגה עצמה לפני,
\begin{קוד}
\cpp{Objective Caml version 3.11.2}
\end{קוד}
ואחר ביקשה ממני קלט נוסף, בהצגה לי את ה\זרז \קד{#}.
כאשר הקלדתי אל \זרז זה את הביטוי \קד{2+2},
תכנת ocaml חישבה את ערכו של הביטוי.
בתום החישוב, הציגה ocaml את הטיפוס של הביטוי שהקלדתי, \מש{int},
ואת ערכו, המספר \קד{4}. ולאחר כל אלו חזרה ocaml והציגה לי שוב את ה\זרז, כדי לציין שהיא ממתינה
לקלט נוסף ממני.
כאשר הקלדתי אל ה\זרז את הביטוי
\begin{קוד}
\let\ttfamily=\listingsfont
\verb+print_string "Hello, World!\n";;+
\end{קוד}
הגיבה ocaml בחישוב הביטוי, ומכיוון שלחישוב זה היתה תוצאת לוואי, הוצג לפני
הסדרית
\begin{קוד}
\listingsfont
Hello, World!
\end{קוד}
לאחר תום החישוב של הביטוי שהקלדתי, הציגה ocaml את הטיפוס של ביטוי זה, \מש{unit}, ואת ערכו
\קד{()}.\הערת␣שוליים{¢¢
אולי אינך מבין את פשר הטיפוס \מש{unit} ואת משמעות הערך \קד{()}. משמעותם
אינה חשובה בשלב זה, והיא תבואר מאוחר יותר, בבואנו לדון בטיפוסים.}
\bash
sed -n /begin/,/end/p < hello.p > hello-body.p
\END
במקום העבודה האינטראקטיבית עם תכנת \שי{ocaml},
יכולתי להכין קובץ המכיל את הקלט אליה:
\begin{קוד}
\bash[script]
cat << EOF >input.caml
2+2;;
print_string "Hello, World!\n";;
EOF
\END
\end{קוד}
ואחרי שהכנתי את הקובץ \קד{input.caml}, אוכל להפעיל את ocaml באופן שבו היא תקרא
ה\קלט שלה מקובץ זה:
\begin{קוד}
\bash[script,stdout]
ocaml < input.caml
\END
\end{קוד}
ה\פלט כולו, כולל ה\זרזים, יוצג על פני המסך. אם לעומת זאת, אפעיל את ocaml
תוך שאני מעביר לה כפרמטר את הקובץ \קד{input.caml}, תכנת ocaml תמנע מלהציג
את הזרז ואת שאר פרטי המידע אותם היא מציגה בעבודה אינטראקטיבית רגילה, אך
תוצאת הלוואי של החישוב תוצג כרגיל:
\begin{קוד}
\bash[script,stdout]
ocaml input.caml
\END
\end{קוד}