מודולה

מוֹדוּלה (באנגלית: Modula) היא שפת תכנות מערכות מובנת ופרוצדורלית עם טיפוסיות חזקה וסטטית שפותחה על ידי ניקלאוס וירת בין השנים 1973–1976 במכון הטכנולוגי של ציריך.<ref name=":1"></ref> מודולה הורחבה במקור מפסקל, וממנה נולד הפיתוח של מודולה־2.<ref></ref> מודולה היא שפת תכנות ניסיונית והפיתוח שלה הופסק לטובת הפיתוח של מודולה־2.<ref name=":1" /><ref></ref><ref name=":0"></ref><ref></ref>

== היסטוריה ==
בשנת 1973 וירת התחיל את הפיתוח של מודולה.<ref name=":1" /> המימוש הראשון שלה הושלם על מחשב PDP-11.<ref name=":1" /><ref name=":0" group="א">Modula, Introduction, pp. 3–5</ref><ref group="א">Modula, PDP-11 Specific Facilities, pp. 29–32</ref>

בשנת 1976 וירת פרסם את האפיון של השפה במכון הטכנולוגי של ציריך.<ref></ref>

בשנת 1977 וירת התחיל את הפיתוח של מודולה־2 כהמשך לפיתוח של מודולה, וכתחליף לפסקל.<ref name=":0" />

== דוגמאות ==
=== מחלק מרבי משותף ===
<syntaxhighlight lang="modula2">
PROCEDURE GCD(n, m: INTEGER): INTEGER;
 VAR a, b: INTEGER;
BEGIN
 WHILE a <> b DO
 IF a < b THEN
 b := b - a
 ELSE
 a := a - b
 END
 END;
 GCD := a
END GCD
</syntaxhighlight>

== עיצוב ==
וירת תכנן שמודולה תהיה היורשת של פסקל.<ref name=":0" group="א" /> אך בנוסף לכך, מודולה תוכננה להיות שפת תכנות מערכות.<ref name=":0" group="א" /> וירת זיהה שבשפות תכנות מערכות יש תלות רבה בין התוכנה לחומרה, וכמעט תמיד הקוד נכתב באופן מותאם לחומרה מסוימת, מה שלא אפשר שימוש חוזר בקוד על מחשבים עם חומרה שונה באותו הזמן.<ref name=":0" group="א" /> על רקע מצב זה, וירת תכנן את מודולה כך שתאפשר הידור נפרד של יחידות קוד מקור על מנת לבודד את הקוד שתלוי במערכת מן הקוד המופשט שאינו תלוי במערכת.<ref name=":0" group="א" /> וירת ויתר על חלק מהמאפיינים של פסקל כשתכנן את מודולה.<ref name=":0" group="א" /> בנוסף, וירת תכנן שמודולה תהיה חוצת ארכיטקטורות וחוצת פלטפורמות ככל הניתן.<ref name=":0" group="א" /> כפי שמסתמן במודולה־2, חידושיה המרכזיים של מודולה על פני פסקל היו:

# מודול כיחידת קוד מקור שעוברת הידור נפרד משאר הקוד.<ref name=":0" group="א" /><ref name=":15" group="א">Modula, Overview, pp. 5–9</ref>
# ריבוי וניהול תהליכים על ידי בתוך הקוד.<ref group="א" name=":16">Modula, Facilities for Multiprogramming, pp. 25–29</ref><ref name=":15" group="א" />

=== טיפוסי נתונים ===
מודולה הכירה רק בארבע טיפוסי נתונים בסיסיים: מספר שלם, ערך בוליאני (אמת או שקר), תו, ומערך סיביות.<ref group="א">Modula, Basic Types, p. 13</ref><ref group="א" name=":3">Modula, Type Declarations, pp. 12–14</ref> לא אופיין מספר ממשי ולא אופיין טיפוס נפרד למחרוזות בשפה, אך היה ניתן ליצור מחרוזת באמצעות מערך תווים.<ref name=":1" group="א">Modula, Constant Declarations, p. 12</ref> אין גישה למצביעים בשפה.<ref name=":15" group="א" />

=== ריבוי תהליכים ===
כשפת תכנות מערכות, מודולה הציעה דרך ליישם בצורה נוחה.<ref name=":16" group="א" /> להכרזת תהליכים בשפה היה תחביר דומה לתחביר של שגרות, אם כי היה ניתן להגדיר תהליכים אך ורק ברמת הקובץ ולא באופן מקונן בתוך רכיבים אחרים.<ref name=":17" group="א">Modula, Processes, pp. 25–26</ref> בשונה משגרות, תהליכים לא היו עוצרים את שאר התוכנה בזמן ריצה, אלא רצים באופן מקביל.<ref name=":17" group="א" /> היה ניתן להריץ תהליכים אך ורק מגוף , ולא בשום מקום אחר בקוד.<ref group="א">Modula, Process Control Statement, p. 26</ref><ref name=":15" group="א" /> בנוסף, מודולים ששיתפו נתונים בין התהליכים הוגדרו בעזרת המילה <code>INTERFACE</code>.<ref name=":18" group="א">Modula, Interface Modules, pp. 25–26</ref> מודולים מסוג זה יצרו תור לכל משתנה בתוכם כדי למנוע מצב שבו שני תהליכים או יותר היו ניגשים לקרוא או לכתוב באותו משתנה באותו הזמן.<ref name=":18" group="א" /> וירת המליץ נגד השימוש במשתנים כדי לסנכרן בין תהליכים, במקום זאת הוא עיצב בשפה אותות מיוחדים לניהול תהליכים מכל מקום בקוד.<ref name=":19" group="א">Modula, Signals, pp. 26–28</ref><ref name=":15" group="א" /> לאותות היה תחביר דומה לזה של קריאת שגרה.<ref name=":19" group="א" /> היו שני סוגי אותות: לעצירת תהליכים, ולהמשך תהליכים.<ref name=":19" group="א" />

== תחביר ==
התחביר של מודולה מורכב מפקודות אימפרטיביות. פקודות מופרדות בעזרת נקודה ופסיק <code>;</code>, ולעיתים קרובות הן גם מכילות ביטויים שעוברים חישוב. פקודות וביטויים מורכבים מאסימונים שנוצרים מרצף תווי ASCII. אסימונים מוכרים מייצגים בין היתר מילים שמורות, ערכים, מחרוזות, הערות, מזהים (שמות של משתנים, קבועים, שגרות, ומודולים), פעולות, ופיסוק.

=== אסימוני השפה ===
{| class="wikitable mw-collapsible"
|+אסימונים במודולה<ref name=":1report" group="א">Modula, Vocabulary and Representation, pp. 10–12</ref>
! colspan="3" |סיווג
!הגדרה
!דוגמה
|-
|מזהה
| colspan="2" |שם משתנה
|רצף של תווי אותיות אלף־בת לטיניות וסיפרות עשרוניות, כשהתו הראשון מוכרח להיות אות.
|<code>i8MyPi</code>
|-
| rowspan="3" |ערך
| rowspan="2" |מספר שלם
|עשרוני
|רצף סיפרות עשרוניות.
|<code>2016</code>
|-
|אוקטלי
|רצף סיפרות עשרוניות בטווח 0–7 ותו <code>B</code> עוקב.
|<code>7B</code>
|-
| colspan="2" |תו
|תו בודד בין זוג תווי <code>'</code>.
|<code>'C'</code>
|-
| rowspan="3" |תחביר
| colspan="2" |פעולה
|כל הופעה של תו המייצג פעולה (ראה פעולות).
|<code>+</code>
|-
| colspan="2" |מילה שמורה
|כל רצף תווים שיוצר מילה מרשימת המילים השמורות.
|<code>IF</code>
|-
| colspan="2" |הערה
|כל רצף שנפתח ב־ ונסגר ב־.
|<code>(* Comment *)</code>
|}

=== מילים שמורות ===
למודולה היו 35 מילים שמורות.<ref name=":1report" group="א" /><syntaxhighlight lang="modula2">
AND				DIV				INTERFACE		PROCEDURE		USE				
ARRAY			DO				LOOP			PROCESS			VALUE			
BEGIN			ELSE			MOD				RECORD			VAR				
CASE			ELSIF			MODULE			REPEAT			WHEN			
CONST			END				NOT				THEN			WHILE			
DEFINE			EXIT			OF				TYPE			WITH			
DEVICE			IF				OR				UNTIL			XOR				
</syntaxhighlight>

=== פעולות ===
{| class="wikitable mw-collapsible"
|+סימני פעולות במודולה<ref name=":1report" group="א" /><ref name=":5" group="א">Modula, Expressions, pp. 15–16</ref>
! colspan="2" |סיווג
!אופרנדים
!פעולה
! colspan="2" |סימן
|-
| rowspan="13" |בינארי
|הקצאה (קלט)
| colspan="2" |קליטת ערך למשתנה
|<code>:=</code>
| rowspan="2" |<math>=</math>
|-
| rowspan="6" |יוחסה
| rowspan="6" |מספרים
|שווה ל־
|<code>=</code>
|-
|לא שווה ל־
|<code><></code>
|<math>\neq</math>
|-
|גדול מ־
|<code>></code>
|<math>></math>
|-
|קטן מ־
|<code><</code>
|<math><</math>
|-
|גדול או שווה ל־
|<code>>=</code>
|<math>\geq</math>
|-
|קטן או שווה ל־
|<code><=</code>
|<math>\leq</math>
|-
| rowspan="2" |לוגיקה
| rowspan="2" |אמת או שקר
|וגם
|<code>AND</code>
|<math>\and</math>
|-
|או
|<code>OR</code>
|<math>\or</math>
|-
| rowspan="4" |חשבון
| rowspan="4" |מספרים
|חיבור
|<code>+</code>
|<math>+</math>
|-
|חיסור
|<code>-</code>
|<math>-</math>
|-
|כפל
|<code>*</code>
|<math>\times</math>
|-
|חילוק שלמים ללא שארית
|<code>/</code>
|<math>\div</math>
|-
| rowspan="2" |אונארי
|לוגיקה
|אמת או שקר
|לא
|<code>NOT</code>
|<math>\neg</math>
|-
|חשבון
|מספר
|סימן שלילי
|<code>-</code>
|<math>-</math>
|}

=== פקודות וביטויים ===
בדומה לשפות תכנות אחרות, פקודות במודולה אפשרו תכנות אימפרטיבי בכך שהן הורו בקרת זרימה והקצאת ביטויים לתוך משתנים,<ref name=":6" group="א">Modula, Statements, p. 16</ref> בעוד שהביטויים עצמם היו רצפים של פעולות ואופרנדים שעוברים חישוב לפי סדר פעולות מתמטי, או סדר פעולות שהמתכנת היה מגדיר בעזרת סוגריים עגולים.<ref name=":5" group="א" /> מודולה הכירה בתשע סוגי פקודות:<ref name=":6" group="א" />

# (קליטת ערך למשתנה) <code>:=</code><ref group="א">Modula, Assignments, p. 16</ref>
# קריאת שגרה<ref name=":7" group="א" />
# כניסה לתוך תחום ההכרזה של השדות ברשומה באמצעות הפקודה <code>WITH</code><ref name=":8" group="א">Modula, With Statements, p. 19</ref>
# שש פקודות לבקרת זרימה:
## תנאי <code>IF</code><ref name=":9" group="א" />
## ניתוב מקרים <code>CASE</code><ref name=":10" group="א" />
## יציאה ידנית מלולאת <code>LOOP</code> באמצעות הפקודה <code>EXIT</code><ref name=":11" group="א">Modula, Loop Statements, pp. 18–19</ref>
## שלוש סוגי לולאות:
### לולאה אין סופית <code>LOOP</code><ref name=":11" group="א" />
### לולאת <code>WHILE</code><ref name=":12" group="א">Modula, While Statements, p. 18</ref>
### לולאת <code>REPEAT</code><ref name=":13" group="א">Modula, Repeat Statements, p. 18</ref>

==== קבועים ====
מודולה אפשרה למתכנת להכריז ערכים קבועים. ערכים אלה אינם משתנים במהלך התוכנית. קבועים הוגדרו בשפה באמצעות מזהה והסימן <code>=</code> ולאחריו הערך (הערך יכול להיות גם מבנה נתונים ולא רק ערך בסיסי).<ref name=":1" group="א" /><syntaxhighlight lang="modula2">
ON = 1
OFF = 0
</syntaxhighlight>

==== משתנים ====
הכרזה של משתנה נעשתה בעזרת הסימן <code>:</code> כשמשמאל שם המשתנה, ומימין טיפוס המשתנה.<ref name=":4" group="א" /><syntaxhighlight lang="modula2">
i, j, k: INTEGER
p, q: BOOLEAN
</syntaxhighlight>

=== בקרת זרימה ===
מהיותה שפת תכנות מבנית, חלק מסוגי הפקודות היו יכולות להכיל בתוכן תת-פקודות. לדוגמה, תנאי <code>IF</code> היה יכול להיות מוכל בתוך תנאי <code>IF</code> אחר, שגם הוא היה יכול להיות מוכל בתוך לולאת <code>WHILE</code>, וכך בעצם הייתה נוצרת בקרת זרימה. במודולה, הסימן נקודה ופסיק <code>;</code> הפריד בין פקודות והגדיר את סדר הביצוע בתוכנית.<ref group="א">Modula, Statement Sequence, p. 17</ref>

===== לולאות =====
מודולה הציעה שלוש סוגי לולאות: <code>WHILE</code>, <code>REPEAT</code>, ו־<code>LOOP</code>.<ref name=":6" group="א" /> כמו בשפות אחרות, הלולאות <code>WHILE</code> ו־<code>REPEAT</code> היו תלויות בתנאי כלשהו. לעומת זאת, בלולאת <code>LOOP</code> נדרשה יציאה ידנית באמצעות הפקודה <code>EXIT</code> בתוכה.<ref name=":11" group="א" /><syntaxhighlight lang="modula2">
LOOP
 i := i + 1 WHEN i = n DO EXIT
END
</syntaxhighlight>בלולאת <code>WHILE</code>, כל עוד התנאי מתקיים, הלולאה תמשיך לחזור על עצמה. דוגמה ללולאת <code>WHILE</code>:<ref name=":12" group="א" /><syntaxhighlight lang="modula2">
WHILE i < n DO
 i := i + 1
END
</syntaxhighlight>בלולאת <code>REPEAT</code>, הבדיקה נעשית בסוף המחזור, והמחזור הראשון מתקיים ללא תנאי. התנאי לעצירה צריך להתקיים על מנת שהלולאה תיעצר. דוגמה ללולאת <code>REPEAT</code>:<ref name=":13" group="א" /><syntaxhighlight lang="modula2">
REPEAT
 i := i + 1
UNTIL i = n
</syntaxhighlight>

===== תנאים =====
הפקודה <code>IF</code> אפשרה בקרת זרימה לפי תנאים. אם התנאי הראשון נכשל, ניתן לשרשר מספר תנאים נוספים אחריו בעזרת <code>ELSIF</code>, ומצב ברירת מחדל באמצעות <code>ELSE</code>.<ref group="א" name=":9">Modula, If Statements, p. 17</ref> תחביר של תנאי מלא היה נראה כך:<syntaxhighlight lang="modula2">
IF n = 0 THEN
 (* n equals 0 *)
ELSIF n = 1 THEN
 (* n equals 1 *)
ELSIF n > 1 THEN
 (* n is greater than 1 *)
ELSE
 (* n is lesser than 0 *)
END
</syntaxhighlight>

==== ניתוב מקרים ====
הפקודה <code>CASE</code> הייתה מחשבת ביטוי כלשהו ואז מבצעת קטע פקודות בהתאם לתוצאה. הקטעים סומנו בעזרת ערך קבוע או ערך מפורש.<ref group="א" name=":10">Modula, Case Statements, p. 18</ref><syntaxhighlight lang="modula2">
CASE N OF
 0: BEGIN (* N equals 0 *) END
 1: BEGIN (* N equals 1 *) END
 2: BEGIN (* N equals 2 *) END
END
</syntaxhighlight>

=== תחום שדות רשומה ===
הפקודה <code>WITH</code> מקבלת רשומה והופכת את השדות שלה לזמינים בתוך הבלוק שלה בלי הצורך להקליד בכל פעם את הכתובת המלאה של השדה עם השם של הרשומה.<ref name=":8" group="א" /><syntaxhighlight lang="modula2">
WITH Account DO
 Balance := 0
END
</syntaxhighlight>

=== מבני נתונים ===
מודולה הכירה בשני מבני נתונים יסודיים: מערך ורשומה.<ref name=":3" group="א" />

==== מערך ====
מערך הוגדר בשפה בעזרת המילה השמורה <code>ARRAY</code>, לאחריו טווח האינדקסים, ולאחר מכן טיפוסיות המערך.<ref name=":2" group="א">Modula, Array Structures, p. 13</ref> לדוגמה, מחרוזת באורך 80 תווים הוגדר כך:<syntaxhighlight lang="modula2">
Line = ARRAY 0:79 OF CHAR
</syntaxhighlight>בנוסף, מערך רב ממדים הוגדר באמצעות רשימה של טווחים.<ref name=":2" group="א" /> לדוגמה, עמוד באורך 256 שורות שבכל אחת מהן יש 80 תווים הוגדר כך:<syntaxhighlight lang="modula2">
Buffer = ARRAY 0:255, 0:79 OF CHAR
</syntaxhighlight>גישה לתוך מערך הייתה מתבצעת בעזרת זוג סוגריים מרובעים <code>[]</code> ובינם האינדקסים מסודרים ברשימה לכל ממד.<ref name=":4" group="א">Modula, Variables, pp. 14–15</ref><syntaxhighlight lang="modula2">
B: Buffer
B[0, 0] := 'C'
</syntaxhighlight>

==== רשומה ====
רשומה הוגדרה בשפה בעזרת המילה השמורה <code>RECORD</code> ואז רשימת השדות והטיפוסיות שלהם (הסימן נקודה ופסיק <code>;</code> הפריד בין השדות).<ref group="א">Modula, Record Structures, p. 14</ref> לדוגמה:<syntaxhighlight lang="modula2">
Account = RECORD
 FirstName: ARRAY 0:255 OF CHAR;
 LastName: ARRAY 0:255 OF CHAR;
 Balance: INTEGER;
 Alive: BOOLEAN
END
</syntaxhighlight>גישה לתוך שדות ברשומה הייתה מתבצעת באמצעות נקודה <code>.</code>.<ref name=":4" group="א" /><syntaxhighlight lang="modula2">
A: Account
A.Alive := TRUE
</syntaxhighlight>

=== שגרות ===
מהיותה שפת תכנות פרוצדורלית, פירקנים במודולה היו עשויים להגדיר תת-תוכניות ולייצא אותם כפקודות עם שמות ייחודיים ופרמטרים. פקודות כאלה נקראות שגרות והן היו מוגדרות בעזרת המילה השמורה <code>PROCEDURE</code>.<ref name=":14" group="א">Modula, Procedures, pp. 19–22</ref> שגרה היא בגדר אם היא מחזירה ערך כלשהו, אחרת היא בגדר .<ref name=":14" group="א" /> פונקציה תחזיר את הערך שהוקצה למזהה שלה.<ref name=":14" group="א" /> הגדרת קבועים ומשתנים מקומיים התאפשרה לפני המילה <code>BEGIN</code>.<ref name=":14" group="א" /> המילה <code>CONST</code> הגדירה את הקבועים, בעוד המילה <code>VAR</code> הגדירה את המשתנים.<ref name=":14" group="א" /> דוגמה לפונקציה ריבועית פשוטה של מספרים שלמים <math>f(n)=n^2</math> כך ש־<math>f:\Z \rightarrow \N</math>:<syntaxhighlight lang="modula2">
PROCEDURE f(n: INTEGER): INTEGER;
BEGIN
 f := n * n;
END f
</syntaxhighlight>
קריאה לשגרה נעשתה בעזרת רשימת ערכים מתאימים לפרמטרים בתוך סוגריים עגולים <code>()</code> מיד אחרי שם השגרה.<ref group="א" name=":7">Modula, Procedure Calls, p. 17</ref><syntaxhighlight lang="modula2">
k := Factorial(4)
</syntaxhighlight>

=== טיפוס נמנים ===
טיפוסי נמנים () הוגדרו בשפה בעזרת זוג סוגריים עגולים <code>()</code> ובתוכם רשימת מזהים מופרדים עם פסיק <code>,</code>.<ref group="א">Modula, Enumerations, p. 13</ref><syntaxhighlight lang="modula2">
weekdays = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)
</syntaxhighlight>

=== מודולים ===
תוכניות במודולה היו בנויות מרכיבים שעברו הידור נפרד זה אחר זה לפי קשר התלות בינם, רכיבים אלו כונו "מודולים" או בעברית "פירקנים."<ref name=":20" group="א">Modula, Modules, pp. 22–25</ref> מבנה המודול הוא גם השלד הבסיסי של כל קובץ קוד מקור בשפה.<ref name=":20" group="א" /> הקטע הבא מתאר את מבנה המודול במודולה.<ref name=":20" group="א" /> בסוף מודול תמיד מופיעה נקודה.<ref name=":20" group="א" /><syntaxhighlight lang="modula2">
MODULE MyModule
 DEFINE f, g; (* List of exported identifiers *)
 USE; (* List of imported identifiers *)
 CONST; (* List of constants *)
 VAR; (* List of variables *)
 (* Some procedures: *)
 PROCEDURE f(x: INTEGER): INTEGER BEGIN END f;
 PROCEDURE g(x: INTEGER): INTEGER BEGIN END g;
BEGIN
 (* Statements *)
END MyModule.
</syntaxhighlight>

== ראו גם ==
* פסקל - שפת התכנות שממנה הורחבה מודולה.<ref name=":1" />
* מודולה־2 - שפת התכנות שירשה את הפיתוח של מודולה.<ref name=":1" />

== לקריאה נוספת ==

== קישורים חיצוניים ==
* 
* [https://rosettacode.org/wiki/Category:Modula-2 דגימות קוד של מודולה ב־RosettaCode] (באנגלית)

== הערות שוליים ==
=== אפיון השפה ===

=== מקורות נוספים ===

קטגוריה:שפות תכנות