Recent from talks
Nothing was collected or created yet.
MAD (programming language)
View on Wikipedia
| MAD | |
|---|---|
| Paradigm | procedural, imperative, structured |
| Family | ALGOL |
| Designed by | Bernard Galler, Bruce Arden, Robert M. Graham |
| Developer | University of Michigan |
| First appeared | 1959 |
| Typing discipline | Static, strong |
| Scope | Lexical |
| OS | UMES, MTS, CTSS, others |
| Major implementations | |
| IBM 704, 7090, S/360, S/370; UNIVAC 1108; Philco 210-211 | |
| Dialects | |
| MAD, MAD/I, GOM | |
| Influenced by | |
| IAL, ALGOL 58 | |
MAD (Michigan Algorithm Decoder) is a programming language and compiler for the IBM 704 and later the IBM 709, IBM 7090, IBM 7040, UNIVAC 1107, UNIVAC 1108, Philco 210-211, and eventually IBM System/370 mainframe computers. Developed in 1959 at the University of Michigan by Bernard Galler, Bruce Arden and Robert M. Graham, MAD is a variant of the ALGOL language. It was widely used to teach programming at colleges and universities during the 1960s and played a minor role in the development of Compatible Time-Sharing System (CTSS), Multics, and the Michigan Terminal System computer operating systems.[1] The original version of the chatbot ELIZA was written in MAD-SLIP.[2]
The archives at the Bentley Historical Library of the University of Michigan contain reference materials on the development of MAD and MAD/I, including three linear feet of printouts with hand-written notations and original printed manuals.[3][4][5][6]
MAD, MAD/I, and GOM
[edit]Three MAD compilers exist:
- Original MAD, the compiler developed in 1959 at the University of Michigan for the IBM 704 and later the IBM 709 and IBM 7090 mainframe computers running the University of Michigan Executive System (UMES) and the Compatible Time-Sharing System (CTSS) operating systems.[7][8] In the mid-1960s MAD was ported at the University of Maryland to the UNIVAC 1108.[9] Versions of MAD were also available for the Philco 210-211 and UNIVAC 1107.[9]
- MAD/I, an "extended" version of MAD for the IBM System/360 series of computers running under the Michigan Terminal System (MTS). Work on the new compiler started in 1965 as part of the ARPA sponsored CONCOMP project at the University of Michigan. As work progressed it gradually became clear that MAD/I was a new language independent of the original 7090 version of MAD.[10]
- GOM (Good Old MAD), a reimplementation of the original 7090 MAD for the IBM System/370 series of mainframe computers running the Michigan Terminal System (MTS). GOM was created in the early 1980s by Don Boettner at the University of Michigan Computing Center.[11][12]
History
[edit]While MAD was motivated by ALGOL 58, it does not resemble ALGOL 58 in any significant way.[13][14]
Programs written in MAD included MAIL,[15] RUNOFF,[16] one of the first text processing systems, and several other utilities all under Compatible Time-Sharing System (CTSS).[17] Work was done on a design for a MAD compiler for Multics, but it was never implemented.[18]
The following is an interesting quote from An Interview with Brian Kernighan[19] when he was asked "What hooked you on programming?":
- I think that the most fun I had programming was a summer job at Project MAC at MIT in the summer of 1966, where I worked on a program that created a job tape for the brand new GE 645 in the earliest days of Multics. I was writing in MAD, which was much easier and more pleasant than the FORTRAN and COBOL that I had written earlier, and I was using CTSS, the first time-sharing system, which was infinitely easier and more pleasant than punch cards.
MAD was quite fast compared to some of the other compilers of its day. Because a number of people were interested in using the FORTRAN language and yet wanted to obtain the speed of the MAD compiler, a system called MADTRAN (written in MAD) was developed. MADTRAN was simply a translator from FORTRAN to MAD, which then produced machine code. MADTRAN was distributed through SHARE.[13]
MAD/I has a syntactic structure similar to ALGOL 60 together with important features from the original MAD and from PL/I.[10] MAD/I was designed as an extensible language. It was available for use under MTS and provided many new ideas which made their way into other languages, but MAD/I compilations were slow and MAD/I never extended itself into widespread use when compared to the original 7090 MAD.[12]
GOM is essentially the 7090 MAD language modified and extended for the 360/370 architecture with some judicious tailoring to better fit current programming practices and problems.[12] The MTS Message System was written in GOM.
MAD, Mad magazine, and Alfred E. Neuman
[edit]
In a pre-release version of the original MAD, as a reference to MAD's namesake, Mad magazine, when a program contained too many compile time errors the compiler would print a full-page picture of Alfred E. Neuman using ASCII art. The caption read, "See this man about your program--He might want to publish it. He never worries--but from the looks of your program, you should."[9] This feature was not included in the final official version.[20] However, it was included in the production version for the IBM 7040.
And Bernie Galler remembers:
- By the time we designed the language that we thought would be worth doing and for which we could do a compiler, we couldn't call it Algol anymore; it really was different. That's when we adopted the name MAD, for the Michigan Algorithm Decoder. We had some funny interaction with the Mad magazine people, when we asked for permission to use the name MAD. In a very funny letter, they told us that they would take us to court and everything else, but ended the threat with a P.S. at the bottom - "Sure, go ahead." Unfortunately, that letter is lost.[21]
"Hello, world" example
[edit]The "hello, world" example program prints the string "Hello, world" to a terminal or screen display.
PRINT FORMAT HELLOW VECTOR VALUES HELLOW=$13h0Hello, world*$ END OF PROGRAM
The first character of the line is treated as logical carriage control, in this example the character "0" which causes a double-spaced line to be printed.
Alternatively, contractions can be used, and the compiler will expand them in the listing:
P'T HELLOW V'S HELLOW=$13h0Hello, world*$ E'M
Language elements
[edit]MAD and GOM, but not MAD/I, are composed of the following elements:[8][12][13]
Input format
[edit]MAD programs are a series of statements written on punched cards, generally one statement per card, although a statement can be continued to multiple cards. Columns 1-10 contains an optional statement label, comments or remarks are flagged using the letter "R" in column 11, and columns 73-80 are unused and could contain a sequence identifier. Spaces are not significant anywhere other than within character constants. For GOM input is free form with no sequence field and lines may be up to 255 characters long; lines that start with an asterisk (*) are comments; and lines that start with a plus-sign (+) are continuation lines.
Names
[edit]Variable names, function names, and statement labels have the same form, a letter followed by zero to five letters or digits. Function names end with a period. All names can be subscripted (the name followed by parentheses, with multiple subscripts separated by commas). For GOM names may be up to 24 characters long and may include the underscore (_) character.
Few keywords in the language are reserved words since most are longer than six letters or are surrounded by periods. There is a standard set of abbreviations which can be used to replace the longer words. These consist of the first and last letters of the keywords with an apostrophe between them, such as W'R for WHENEVER and D'N for DIMENSION.
Data types
[edit]MAD uses the term "mode" for its data types. Five basic modes are supported:
- Integer written with or without a scale factor (1, +1, -1, 1K10, 1K) or as octal constants (to 7777777777777K);
- Floating Point written with or without an exponent (0., 1.5, -0.05, +100.4, -4., .05E-2, -.05E2, 5E02, 5.E2);
- Boolean (1B for true and 0B for false);
- Statement Label, and
- Function Name written as a name followed by a period (SQRT.).
The mode of a constant can be redefined by adding the character M followed by a single digit at the end of the constant, where 0 indicates floating point, 1 integer, 2 boolean, 3 function name, and 4 statement label.
For GOM six additional modes are added: CHARACTER, SHORT INTEGER, BYTE INTEGER, LONG INTEGER, POINTER, and DYNAMIC RECORD.
Alphabetic or character constants are stored as integers and written using the dollar sign as a delimiter ($ABCDEF$) with double dollar-signs used to enter a true dollar sign ($$$.56$ is 56 cents). Strings longer than six characters are represented using arrays.
Arrays and matrices
[edit]- There is no limit on the number of dimensions.
- Negative and zero as well as floating-point subscripts are allowed.
- Matrices are storied in consecutive memory locations in the order determined by varying the rightmost subscript first.
- Matrices may be referenced using a subscript for each dimension, NAME(s1,s2,s3), or using a single subscript, NAME(s1).
- Input-output lists, VECTOR VALUES statements, and some subroutines allow the use of block notation, which has the form A,...,B or A...B, which is a reference to the entire region from A to B. inclusive. In terms of a vector, A(1)...A(N) would be A(1), A(2), A(3), ..., A(N).
- There are facilities that allow changing dimensions at run-time; permitting the programmer to vary the location of the initial element in an array within the overall block which has been set aside for the array; and allowing an arbitrary storage mapping to be specified.
Operators
[edit]
Arithmetic operators[edit]
Pointer operators (GOM only)[edit]
|
Relational operators[edit]
Boolean operators[edit]
Bit operators (GOM only)[edit]
|
Declaration statements
[edit]Variables may be implicitly or explicitly declared. By default all implicitly declared variables are assumed to be floating point. The NORMAL MODE IS statement may be used to change this default.
|
|
Executable statements
[edit]
|
|
Input and output statements
[edit]
|
|
Functions
[edit]Function names end with a period. Internal and external functions are supported. Internal functions are compiled as part of the program in which they are used and share declarations and variables with the main program. External functions are compiled separately and do not share declarations and variables. A one statement definition of internal functions is permitted. Recursive functions are permitted, although the function must do some of the required saving and restoring work itself.
|
|
Operator definition and redefinition
[edit]One of the most interesting features in MAD is the ability to extend the language by redefining existing operators, defining new operators, or defining new data types (modes). The definitions are made using MAD declaration statements and assembly language mnemonics included following the declaration up to the END pseudo-instruction that implement the operation.
- DEFINE BINARY OPERATOR defined-op, PRECEDENCE rank existing-op MODE STRUCTURE mode-options
- DEFINE UNARY OPERATOR defined-op, PRECEDENCE rank existing-op MODE STRUCTURE mode-options
- MODE STRUCTURE mode-no = mode-no existing-op mode-no
- MODE STRUCTURE mode-no = mode-no existing-op mode-no SAME SEQUENCE AS mode-no existing-op mode-no
where:
- rank is one of SAME AS, LOWER THAN, or HIGHER THAN; and
- mode-options are the options that appear on the MODE STRUCTURE statement.
Three pre-defined packages of definitions (MATRIX, DOUBLE PRECISION, and COMPLEX) are available for inclusion in MAD source programs using the INCLUDE statement.
- INCLUDE package
See also
[edit]Notes
[edit]- ^ Alt, Franz (1967). Advances in Computers. Academic Press. p. 143. ISBN 0-12-012104-2.
- ^ Shrager, Jeff. "Joseph Weizenbaum's Original ELIZA". Archived from the original on August 13, 2021. Retrieved January 12, 2023.
- ^ Technical Memos, University of Michigan Computing Center publications, 1965-1999
- ^ Technical Reports, University of Michigan Computing Center publications, 1965-1999
- ^ Topical File 1960-1986, University of Michigan Computing Center records, 1952-1996
- ^ MAD (Michigan Algorithm Decoder) 1960-1979, University of Michigan Computing Center records, 1952-1996
- ^ A User's Reference Manual For The Michigan Algorithm Decoder (MAD) For the IBM 7090, Digital Computer Laboratory, Graduate College, University of Illinois, 1962, 221 pages
- ^ a b The Michigan Algorithm Decoder (The MAD Manual), Bruce W. Arden, Revised Edition 1966
- ^ a b c George Gray (June 2002). "UNIVAC and ALGOL". Unisys History Newsletter. 6 (2). Archived from the original on June 29, 2017.
- ^ a b The MAD/I Manual, Bolas, Springer, and Srodawa, CONCOMP Technical Report 32, 1970, University of Michigan, Ann Arbor, 194 pages
- ^ MTS Volume 2: Public File Descriptions, University of Michigan Computing Center, 1990, p. 14
- ^ a b c d GOM Manual, Don Boettner, University of Michigan Computing Center, Ann Arbor, June 1989
- ^ a b c Computer Languages - Principles and History
- ^ In August 2010 when asked about Jean's Sammet's statement that "MAD does not resemble ALGOL 58 in any significant way", Bruce Arden wrote: "Regarding Jean Sammet, she may have conflated the two versions of IAL (58 and 60). Unlike the later version, the 58 version said nothing about what words (or language) should be used to identify conditional and transfer statements, which led for parsing reasons to words like WHENEVER. Also there were some additional features in MAD that went beyond the 58 specs."
- ^ Documentation and Source for Early Electronic Mail and Messaging, Tom Van Vleck
- ^ "... Doug McIlroy and Bob Morris wrote Multics runoff in BCPL based on Jerry Saltzer's MAD version of RUNOFF for CTSS.", "Multics Software Features: Section 1.7.7", Multicans Web site. Retrieved November 10, 2018.
- ^ Compatible Time-Sharing System (1961-1973): Fiftieth Anniversary Commemorative Overview, David Walden and Tom Van Vleck (Eds), 2011, IEEE Computer Society. Retrieved November 10, 2018.
- ^ "Glossary of Multics acronyms and terms", Tom Van Vleck, Multicans Web site.
- ^ Noren, Allen (April 10, 2009). "An Interview with Brian Kernighan: Breeding Little Languages". O'Reilly Community. Archived from the original on June 30, 2017. Retrieved July 28, 2023.
- ^ Shneiderman, Ben; Plaisant, Catherine (May 7, 2004). Designing the user interface (4th ed.). Addison Wesley. ISBN 978-0-321-19786-3.
- ^ Galler, Bernard A.; Galler, Enid H. (January 2001). "A Career Interview with Bernie Galler". IEEE Annals of the History of Computing. 23 (1): 22–33. doi:10.1109/85.910847. ISSN 1058-6180.
References
[edit]- An Abbreviated description of the MAD compiler language, Fernando J. Corbató, Jerome H. Saltzer, Neil Barta, and Thomas N. Hastings, M.I.T. Computation Center Memorandum CC-213, June 1963.
- CLSYS, a program to facilitate the use of the MAD translator for large (class-size) batches, Jerome H. Saltzer, M.I.T. Computation Center Memorandum CC-204. February 1963.
- A Computer Primer for the Mad Language, Elliott Irving Organick, 1961.
- Internal organization of the MAD translator, Arden, B. W., Galler, B. A. and Graham, R. M., pp. 28–31, CACM Volume 4 No. 1 (Jan 1961)
- An Introduction To Algorithmic Methods Using The MAD Language, Alan B. Marcovitz and Earl J. Schweppe, Macmillan, 1966.
- An Introduction to Digital Computers and the MAD Language, Brice Carnahan, University of Michigan.
- The Language of Computers, Bernard A. Galler, University of Michigan, McGraw-Hill, 1962.
- MAD at Michigan: its function & features, Arden, B. W., Galler, B. A., and Graham, R. M., pp27–28, Datamation, Volume 7 No. 12 (Dec 1961)
- Flow Charts of The Michigan Algorithm Decoder, by G. B. Smith, SHARE General Program Library, SHARE Distribution Number 1327 PA, 1961
External links
[edit]- Eric Raymond's retrocompiler for MAD
- A trivial example of a MAD program
- Dave Pitts' IBM 7094 support – Has a CTSS environment that includes the MIT version of MAD.
MAD (programming language)
View on GrokipediaOverview and Variants
Core MAD Language
The Michigan Algorithm Decoder (MAD) is a procedural, imperative, and structured programming language developed in 1959 at the University of Michigan Computing Center as a variant of ALGOL 58, designed specifically for expressing algorithms in a clear and precise manner suitable for early digital computers.[1] It functions as both a language and a compiler that translates high-level algorithmic descriptions into equivalent machine instructions, emphasizing readability and ease of use for scientific and computational tasks.[1] Key designers of the original MAD included Bernard Galler, Bruce Arden, and Robert M. Graham, who collaborated to create its foundational structure.[3] The language primarily targeted IBM mainframes such as the 704, 709, and 7090, leveraging their capabilities for numerical computations in academic and research environments.[4] MAD's core goals centered on facilitating programming education by providing an intuitive syntax akin to ALGOL for describing algorithms, while enabling direct translation to machine code to support efficient scientific computing on limited hardware.[1] Among its initial features, MAD introduced extensibility through user-defined operators and data types, allowing programmers to customize the language for specific needs, and it supported multi-dimensional arrays with flexible indexing, including up to seven dimensions, dynamic sizing, and even negative or zero subscripts for advanced data handling.[4][1] Later adaptations, such as MAD/I and GOM, built upon this baseline for newer systems.[1]MAD/I
MAD/I is a variant of the MAD programming language, conceived in 1965 at the University of Michigan Computing Center as an adaptation for the IBM System/360 architecture and sponsored by the Advanced Research Projects Agency (ARPA) under the CONCOMP project.[5] This development aimed to extend MAD's capabilities to the new third-generation computers, with the compiler becoming operational by late 1968.[5] The original MAD, designed for earlier IBM 704/709 systems, provided the foundational concepts but required significant updates for System/360 compatibility. Key differences from the core MAD include a syntactic structure more closely aligned with ALGOL 60, incorporating block structures and elements from PL/I while retaining algebraic features from MAD.[5][6] MAD/I introduced expanded definitional facilities, new data types such as dynamic storage, and extensibility through user-defined macros and statement structures, making it less compatible with the 7090-era MAD but better suited for modern applications.[6] These changes improved portability across IBM System/360 models, particularly the Model 67 with virtual memory support, though the language remained somewhat machine-dependent due to System/360-specific features like data set handling.[5][6] Implementation details include the MAD/I compiler, which produces object modules compatible with the Michigan Terminal System (MTS), a timesharing extension for System/360.[5] A translation tool, MADTRAN, facilitated converting FORTRAN programs to MAD/I equivalents, yielding performance gains through MAD/I's efficient compilation and execution on System/360 hardware.[7] The language's definitional facilities further supported custom translators for integrating code from other languages.[5] In usage contexts, MAD/I integrated with operating environments like MTS on System/360 Model 67, enabling conversational and timesharing modes that extended beyond batch processing.[6] It found application in larger-scale scientific computing, including algebraic manipulations, symbol processing, and graphical data structures, benefiting from System/360's increased capacity for complex simulations and research programs.[6][5]GOM
GOM, also known as Good Old MAD, represents an early 1980s reimplementation and extension of the original MAD language for the IBM System/370 architecture under the Michigan Terminal System (MTS). Developed by Don Boettner at the University of Michigan Computing Center, it adapted the 7090-era MAD dialect to support machine-dependent programming and operating system components on the 360/370 family.[8][9] This variant built briefly on structural influences from earlier adaptations like MAD/I, enhancing portability and expressiveness for mainframe environments. Key improvements included free-form input supporting lines up to 255 characters, allowing greater flexibility in code formatting compared to fixed-column predecessors.[10][10] Identifier handling was expanded to permit names up to 24 characters, including underscores after an initial letter, facilitating more descriptive variable and function naming. Additional data types were introduced, such as CHARACTER for string manipulation and SHORT INTEGER for compact numeric storage, alongside variants like BYTE INTEGER and LONG INTEGER to align with System/370's addressing capabilities.[10][10] Exclusive to GOM were specialized operators for advanced operations: pointer operators including .LOC. for location addressing and .IND. for indirect referencing, as well as bit-level operators like .SETBIT. and .RESETBIT. for direct manipulation of binary data. These features enabled low-level system programming tasks integral to MTS development.[10] The definitive reference is the GOM Manual (June 1989), authored by Donald Boettner and archived in the University of Michigan's Deep Blue repository, which details its full syntax, extensions, and implementation guidelines.[9]History
Development Origins
The development of MAD (Michigan Algorithm Decoder) originated at the University of Michigan Computing Center, where it was conceived between 1958 and 1959 as a response to the need for a more practical algorithmic programming language. The project was led by a team of researchers including Bruce W. Arden, Bernard A. Galler, and Robert M. Graham, who divided responsibilities across the compiler's components: Graham handled the initial parser in the front end, Arden developed the back end for code generation, and Galler contributed to the overall language design and subsequent parts of the implementation.[3][11] The first implementation of MAD was completed on the IBM 704 in 1959, with the system becoming fully operational by early 1960. This timeline reflected the rapid evolution from design to deployment, driven by the team's dissatisfaction with the theoretical complexities of emerging standards. Primarily influenced by ALGOL 58—the International Algebraic Language proposed in 1958—MAD adopted its block-structured syntax and expression-oriented approach but diverged substantially to prioritize ease of implementation on IBM hardware, avoiding features deemed too abstract or inefficient for practical computing environments. As Bernard Galler later recalled, "We decided to do an ALGOL 58 compiler... by the time we designed the language... we said we couldn’t call it ALGOL any more; it really was different."[3][11] MAD was envisioned as one of the earliest extensible programming languages, incorporating mechanisms that allowed users to define custom operators and notations, setting it apart from rigid contemporaries like FORTRAN. Its core purpose centered on translating high-level algorithms directly into machine code, with a strong emphasis on supporting educational instruction in programming concepts and facilitating scientific computations at academic institutions. This focus made MAD particularly valuable for teaching and research, where flexibility and readability were essential for non-expert users exploring numerical and algorithmic problems.[3][12][2]Implementations and Adoption
MAD was initially implemented for the IBM 709 and 7090 computers in 1960, serving as a compiler for algorithmic descriptions on these early mainframes.[1] Ports followed to other systems, including the UNIVAC 1108 in the mid-1960s at the University of Maryland, and versions for the Philco 210-211 (part of the Philco 2000 series) and UNIVAC 1107.[3][4] An extended variant, MAD/I, was developed for the IBM System/360 architecture around 1965, providing enhanced features like definitional facilities for user-defined operators and data types, and was integrated into the Michigan Terminal System (MTS).[5] By the 1980s, the GOM implementation extended MAD compatibility to the IBM System/370, adapting the original 7090 syntax for the newer architecture while maintaining procedural elements.[13] The language played a role in developing key early operating systems, including portions of the Compatible Time-Sharing System (CTSS) at MIT, where it was used for system programming due to its block structure and fast compilation.[14] It contributed minor elements to Multics design efforts, though PL/I ultimately prevailed, and supported core components of MTS at the University of Michigan.[15] Notable applications included the ELIZA chatbot, implemented in 1966 using the MAD-SLIP library for list processing on CTSS, enabling pattern-matching conversations.[16] Utilities like the MAIL program for CTSS, written by Tom Van Vleck in 1965, and RUNOFF, a text formatting tool by J. H. Saltzer for thesis preparation, were also coded in MAD, influencing later tools like nroff.[17][18] Adoption peaked in the 1960s and 1970s, with MAD widely taught in university curricula for its accessibility in scientific computing, gaining broad use at institutions like the University of Michigan, MIT, and the University of Maryland, as well as industry sites such as Ford Motor Company.[3] To facilitate migration of existing code, MADTRAN, a preprocessor developed at MIT, translated FORTRAN II programs to MAD for faster execution and easier maintenance.[19] By the late 1970s, MAD's prominence declined as FORTRAN, PL/I, and emerging languages like C offered broader support and portability on evolving hardware, leading to its gradual obsolescence outside niche academic environments. Archival materials, including development records and manuals, are preserved at the University of Michigan's Bentley Historical Library.[20]Cultural References
Mad Magazine Connection
The acronym MAD, standing for Michigan Algorithm Decoder, was selected by its developers at the University of Michigan in 1959 as a backronym for their ALGOL-inspired language, independent of the contemporaneous humor magazine Mad. To ensure legal clearance, the team sought permission from the magazine's publishers, receiving a humorous response letter that initially threatened litigation but concluded with a postscript granting approval.[11] This exchange highlighted the serendipitous naming overlap, which the developers embraced by incorporating playful references to the magazine in the language's ecosystem. A notable cultural tie-in appeared in the early MAD compiler's error handling, where severe compilation failures triggered output of an ASCII art depiction of Alfred E. Neuman, the iconic Mad mascot, accompanied by the phrase "What, Me Worry?" printed on line printers like those connected to the IBM 704.[21] This whimsical diagnostic, an early example of programmer humor in computing, was featured in developmental versions around 1960.[22] These elements infused levity into the often frustrating process of programming, particularly in university settings where MAD was a staple for teaching algorithmic concepts during the 1960s. Despite the fun nods, there was no direct influence from the magazine on the language's technical design, which remained focused on computational efficiency and accessibility.[11]Example Programs
Hello World Implementation
A canonical "Hello, world" program in the core MAD language demonstrates basic output using format declarations and vector presetting for string data. This simple program declares a format for printing and presets a vector containing the message, including carriage control, before ending execution.[1]PRINT FORMAT HELLOW
VECTOR VALUES HELLOW=$13H0Hello, world*$
END OF PROGRAM
PRINT FORMAT HELLOW
VECTOR VALUES HELLOW=$13H0Hello, world*$
END OF PROGRAM
PRINT FORMAT statement specifies the output format named HELLOW, which is then populated via the VECTOR VALUES declaration. This assigns a Hollerith string to the vector, using Hollerith notation (13H to indicate 13 characters, including the carriage control '0' and the 12-character message "Hello, world"), delimited by $ and terminated by *. Upon execution, the program outputs the string "Hello, world" to the printer or terminal with double spacing, as interpreted by the system's I/O handler.[1][23]
This example executes on original MAD implementations for IBM 704, 709, and 7090 systems, typically compiled from punched card input and producing direct textual output without further processing.[1]
Syntax Fundamentals
Input Format
The input format for the MAD programming language was designed around the punched card technology prevalent in early computing environments, enforcing a rigid columnar structure to facilitate mechanical reading and processing by compilers on systems like the IBM 704 and 709. Each statement typically occupied one 80-column punched card, with columns 1 through 10 reserved for optional statement labels, column 11 used to indicate continuations (via digits 1 through 9 for subsequent cards of a multi-card statement, up to a maximum of 10 cards) or remarks (marked with an "R" for comments ignored by the compiler), columns 12 through 72 dedicated to the statement text itself, and columns 73 through 80 for optional sequence numbers or identification not processed by the computer. This fixed format ensured compatibility with card readers, where blanks were generally ignored except within specific contexts like Hollerith strings, and statements could not split fields across cards without proper continuation markers.[1] Within this columnar layout, MAD statements followed a semi-free-form approach in columns 12-72, allowing flexible spacing for readability while keywords—such as READ, PRINT, or DIMENSION—were conventionally entered in uppercase letters, as shown in examples. Labels, when present, adhered to the rules for identifiers but were positioned anywhere within columns 1-10 without affecting the statement's execution. The compiler's error diagnostics were directly tied to these card positions, referencing specific columns in output messages to aid debugging, with remarks in column 11 associating explanatory notes to the preceding statement for contextual reference during compilation.[1] Subsequent implementations, such as GOM (Good Old MAD), evolved the input format away from punched cards toward a more flexible, free-form structure suitable for terminal-based entry on IBM System/360 and later systems, permitting lines up to 255 characters long without a sequence field, where statements begin after the first non-blank character if column 1 is empty, and continuations are marked by a "+" in column 1 of the following line. In GOM, comments are initiated by an asterisk (*) in column 1, extending to the end of the line, while the core MAD format retained its card-based columnar rigidity in earlier ports and documentation. This shift in GOM enhanced usability for interactive environments but preserved backward compatibility with MAD's foundational syntax rules.[10]Identifiers and Names
In the MAD programming language, identifiers for variables, functions, and statement labels consist of one to six alphanumeric characters, with the first character required to be a letter from A to Z.[1] This structure ensures compatibility with the punched-card input format prevalent on early IBM systems like the 7090, where names were limited to fit within fixed column constraints. Digits may follow the initial letter, but the total length cannot exceed six characters to maintain parseability by the compiler.[1] Function names in MAD follow the same alphanumeric rules but must terminate with a period to distinguish them from variables, such as SIN. or COS.(X).[1] Statement labels adhere to identical naming conventions and are placed in specific card columns (1-10) for transfer statements like GO TO.[1] Certain keywords are reserved and cannot be repurposed as identifiers, including PRINT for output operations and VECTOR for array declarations, as they are integral to the language's syntax and would cause compilation errors if redefined.[1] The GOM implementation of MAD, designed for IBM System/360 and later systems, extends these rules to support longer identifiers of up to 24 characters, incorporating underscores as valid components alongside letters and digits, while still requiring the first character to be a letter.[10] This enhancement improves readability for larger programs without breaking backward compatibility.[10] Reserved words remain prohibited for use as identifiers in GOM, preserving keywords like PRINT and VECTOR to avoid conflicts with core language features.[10] Regarding scope, identifiers in MAD and GOM are local by default to the block or function in which they are declared, limiting accessibility to that context unless explicitly designated as global via PROGRAM COMMON statements.[1][10] This scoping mechanism influences how names are resolved during compilation, ensuring no unintended overlaps, and ties directly into declaration statements where identifiers are assigned modes like INTEGER or FLOATING POINT.[1]Data Structures
Data Types
The MAD programming language supports a set of built-in data types designed for algorithmic and scientific computing on early mainframe systems, primarily the IBM 704, 709, and 7090. These types include INTEGER for fixed-point arithmetic, FLOATING POINT for real numbers, BOOLEAN for logical values, STATEMENT LABEL for control flow, and FUNCTION NAME for subroutine references. Variables are declared using mode statements such as INTEGER or FLOATING POINT, which specify the type and ensure type-appropriate operations; undeclared variables default to FLOATING POINT mode.[1] INTEGER represents whole numbers without fractional parts, suitable for indices, counters, and efficient integer arithmetic. Constants are decimal digits up to 10 in length, optionally with an octal prefix (e.g., 127K2) or scale factor (e.g., 1K10), ranging from -2^35 to 2^35 - 1. Declaration example:INTEGER J, N. Operations include integer division, which truncates toward zero (e.g., 16 / 20 yields 0). FLOATING POINT handles real numbers with decimal points or scientific notation (e.g., 1.5 or .05E-2), supporting exponents from -38 to +38 for scientific computations. It is the default mode, declared as FLOATING POINT X, and used for most arithmetic unless specified otherwise.[1]
BOOLEAN encapsulates logical true (1B) or false (0B) values, employed in conditional expressions with operators like .AND. and .OR. Declared via BOOLEAN P, Q, it supports relational comparisons and is convertible to INTEGER for indexing. STATEMENT LABEL identifies jump targets in control statements like TRANSFER TO, using alphanumeric identifiers (1-6 characters, starting with a letter) placed in the label field (e.g., IN:). Declared as STATEMENT [LABEL](/page/Label) ALPHA. FUNCTION NAME denotes user-defined or built-in functions, suffixed with a period when invoked (e.g., SIN.(X)), and declared as FUNCTION NAME FACTO for custom subroutines. Alphabetic constants, treated as a form of CHARACTER data, use dollar-delimited strings up to 6 characters (e.g., ), stored as padded integer codes for output formatting.[1]
The GOM dialect, an extension of MAD for the IBM System/360, introduces additional types including CHARACTER for strings and SHORT INTEGER for reduced-precision integers. CHARACTER stores case-sensitive text as 1-byte elements, declared as CHARACTER NAME(3), with constants delimited by A or "ABC"), supporting substring access like NAME(0...3). SHORT INTEGER uses 2 bytes for values from -32768 to +32767, declared as SHORT INTEGER VAR or with qualifiers like 1@SI for constants, and automatically promotes to full INTEGER in expressions for compatibility.[10]
Type conversions in MAD occur implicitly during expression evaluation: INTEGER values promote to FLOATING POINT in mixed arithmetic, while FLOATING POINT to INTEGER truncates the fractional part. BOOLEAN converts to INTEGER (1 or 0) for use in formats or indices. Explicit conversions use functions or qualifiers like .AS. INTEGER for casting without arithmetic adjustment. These mechanisms ensure flexibility while preserving precision where declared.[1][10]
Arrays and Matrices
MAD supports multi-dimensional arrays through declarations in mode statements that specify the dimensions and data type, allowing for flexible storage of collections of elements. Arrays are declared by including dimensions in parentheses after the array name in the mode declaration, such asINTEGER A(10,20), which allocates space for a two-dimensional array with 10 rows and 20 columns of integer elements. The DIMENSION statement can be used separately to specify or adjust sizes, e.g., DIMENSION A(10,20).[1]
Dimensions can include ranges with lower and upper bounds using double dots (..), supporting negative indices; for example, FLOATING B(-5..5, 0..10) creates an 11-by-11 floating-point array indexed from -5 to 5 in the first dimension and 0 to 10 in the second. For one-dimensional arrays (vectors), the lower bound defaults to 0 if not specified (e.g., A(10) indexes 0 to 10); for multi-dimensional arrays, it defaults to 1. The total storage is computed as the product of the dimension sizes, with each element occupying space based on the type (e.g., one word for integers, two for floating-point).[1]
Indexing in MAD provides significant flexibility, permitting subscripts that are integers, negative numbers, zero, or even floating-point values truncated to integers. Elements are accessed using parentheses with comma-separated subscripts, as in A(I,J) where I and J are expressions evaluating to valid indices within the declared bounds; out-of-bounds access may lead to undefined behavior or program halt depending on the implementation. For arrays of dimension three or greater, subscripts must be integer mode. Additionally, block notation enables range specifications for operations like input/output or iteration, such as A(3..5, 10) to refer to a subarray or C(1)..C(10) for a sequence of one-dimensional elements, which is particularly useful for efficient data handling without explicit loops.[1] Multi-dimensional arrays are stored in a linear fashion, with the last subscript varying fastest (row-major order), computed via a linear index formula like r = n*(i-1) + (j-1) + base for a 2D array, allowing equivalent access with a single subscript if needed.[1]
For matrix-specific operations, MAD includes a MATRIX package accessed via the INCLUDE statement, which provides functions for linear algebra tasks such as transposition, inversion, and multiplication on declared arrays treated as matrices. For instance, after INCLUDE MATRIX, a statement like D = TRANS.(A, N) computes the transpose of an N-by-N matrix A into D, assuming A is suitably dimensioned.[1] This package supports symmetric and sparse matrices through specialized subscription functions like SYMM for symmetric storage, reducing memory usage by storing only upper or lower triangles.[1]
Storage for arrays and matrices is dynamically allocated at compile time based on the declaration dimensions, with the total size determining the block of memory reserved in the program's data area. The SETDIM statement allows runtime modification of dimensions for certain arrays, such as SETDIM(A, M, N) to resize an array A to M rows and N columns, though this requires careful management to avoid overwriting other data.[1] Elements within arrays can reference base data types like INTEGER or FLOATING, ensuring type consistency across the structure.[1]
Operators and Expressions
Arithmetic and Relational Operators
The MAD programming language supports a set of predefined arithmetic operators for performing numerical computations within expressions. These include addition (+), subtraction (-), multiplication (*), division (/), and exponentiation (.P.). The addition operator computes the sum of two operands, as in X + Y. Subtraction yields the difference, for example X - Y. Multiplication performs the product X * Y, while division X / Y produces a result that is truncated toward zero if both operands are integers; otherwise, it yields a floating-point quotient. Exponentiation raises the left operand to the power of the right, denoted as X .P. Y. Additionally, unary negation (-X) and the absolute value function (.ABS.(X)) are available for arithmetic manipulation.[1]
Relational operators in MAD facilitate comparisons between operands, producing Boolean results for use in conditional expressions. These operators are equality (.E.), inequality (.NE.), less than (.L.), greater than (.G.), less than or equal to (.LE.), and greater than or equal to (.GE.). For instance, X .E. Y evaluates to true if X equals Y, while X .G. Y checks if X is greater than Y. These operators apply to numeric types and follow standard comparison semantics, with relational expressions yielding Boolean values that can be combined in conditions.[1]
Arithmetic and relational operators are integral to MAD expressions, which combine variables, constants, and function calls according to operator precedence and associativity rules. Expressions support implicit type conversion where necessary, such as promoting integers to floating-point during mixed operations. A representative arithmetic expression is A = B * C + 5, which assigns the value of (B * C) + 5 to A. For relational usage, an example is IF X .LE. 0 THEN ..., testing if X is less than or equal to zero. Parentheses can override precedence to enforce desired evaluation order, such as (A + B) * C.[1]
Operator precedence in MAD determines the parsing order of expressions, with higher precedence operators binding tighter. The absolute value .ABS. has the highest precedence among arithmetic functions (level 14, right-associative), followed by exponentiation .P. (level 11, right-associative), then multiplicative operators * and / (level 9, left-associative), additive operators + and - (binary, level 8, left-associative), and unary negation (-, level 10, right-associative). Relational operators have the lowest precedence among these (level 7, left-associative). The hierarchy for core arithmetic operators is summarized below:
| Precedence Level | Operators | Associativity | Description |
|---|---|---|---|
| 14 (highest) | .ABS. | Right | Absolute value |
| 11 | .P. | Right | Exponentiation |
| 10 | unary - | Right | Negation |
| 9 | *, / | Left | Multiplication, division |
| 8 (lowest for arithmetic) | +, - (binary) | Left | Addition, subtraction |
Boolean and Bit Operators
MAD supports boolean operators for performing logical operations on boolean values, which are represented as1B for true and 0B for false. The primary boolean operators are .AND. for logical conjunction, .OR. for logical disjunction, and .NOT. for logical negation. These operators take boolean operands and produce a boolean result. Additional operators include .EXOR. for exclusive or (true if operands differ) and .EQV. for equivalence (true if operands are the same).[1][10]
Boolean expressions are evaluated from right to left, with short-circuit evaluation applied to chains of .AND. and .OR.: in a conjunction, evaluation stops if any operand is 0B; in a disjunction, it stops if any operand is 1B. Relational operators (such as .G. for greater than) produce boolean results, allowing seamless integration into boolean expressions, such as (X .G. 3 .AND. Y .LE. 2) .OR. (GAMMA .L. [EPSILON](/page/Epsilon)).[1]
The truth tables for the core boolean operators are as follows:
| Operand 1 | Operand 2 | .AND. | .OR. | .EXOR. | .EQV. |
|---|---|---|---|---|---|
| 0B | 0B | 0B | 0B | 0B | 1B |
| 0B | 1B | 0B | 1B | 1B | 0B |
| 1B | 0B | 0B | 1B | 1B | 0B |
| 1B | 1B | 1B | 1B | 0B | 1B |
.NOT., it inverts the operand: .NOT. 0B yields 1B, and .NOT. 1B yields 0B.[1]
Bitwise operators in MAD enable manipulation of integer bit patterns, applicable to integer modes. These include .A. for bitwise AND, .V. for bitwise OR, .EV. for bitwise exclusive OR, and .N. for bitwise negation (one's complement). MAD also provides .LS. for left shift and .RS. for right shift by a non-negative integer amount. In the GOM dialect, additional operators .SETBIT. and .RESETBIT. allow setting or clearing specific bits (e.g., ABC .SETBIT. 24 sets the 24th bit of ABC to 1).[1][10]
Bitwise operations follow the same right-to-left evaluation as boolean expressions but without short-circuiting, producing an integer result. For example, if I = 17 (binary ...00010001) and J = 9 (binary ...00001001), then I .A. J yields 1 (binary ...00000001), I .V. J yields 25 (binary ...00011001), I .EV. J yields 24 (binary ...00011000), and .N. I performs bitwise inversion across the full word (36 bits on IBM 7090), resulting in a large negative value in one's complement representation. These operators are useful for low-level bit manipulation in MAD and GOM programs.[1][10]
Boolean expressions, including those incorporating relational results, are commonly used in control structures such as IF statements for conditional execution.[1]
Control and Execution
Declaration Statements
Declaration statements in the MAD programming language, particularly in its MAD/I variant, are used to define variables, arrays, labels, and functions, specifying their types, scopes, and storage attributes before they can be used in a program. These statements ensure that identifiers are properly allocated in the symbol table at compile time, preventing runtime ambiguities and enabling type checking. The primary form is the DECLARE statement, which allows explicit assignment of modes and qualifiers to one or more identifiers.[5] The syntax for a basic variable declaration isDECLARE identifier mode, where mode specifies the data type, such as INTEGER for whole numbers or FLOATING for real numbers. For example, DECLARE X FLOATING POINT declares a variable X as a floating-point number, defaulting to short precision unless specified otherwise (e.g., FLOATING LONG). Multiple identifiers can be declared together, as in DECLARE A, B [INTEGER](/page/Integer). An alternative "inverted" syntax places the mode first, followed by the identifier list, such as [INTEGER](/page/Integer) A, B, which is equivalent to the explicit DECLARE form and provides a more concise notation for simple cases. Array declarations extend this by including bounds, using DECLARE identifier FIXED [ARRAY](/page/Array) (bounds) mode, for instance DECLARE ARR FIXED [ARRAY](/page/Array) (1..10) [INTEGER](/page/Integer) to create a fixed-size integer array with indices from 1 to 10. Varying arrays, which allow runtime dimension changes, follow a similar syntax but with VARYING ARRAY, though their implementation was limited in early versions.[5]
Labels and functions are declared using specialized modes like TRANSFER POINT for statement labels or ENTRY POINT for callable functions. A label declaration might appear as DECLARE LBL TRANSFER POINT, allowing LBL to be used as a goto target, while functions are declared as DECLARE FUNC [ENTRY POINT](/page/Entry_point) mode, specifying the return type if applicable, such as DECLARE FACT [ENTRY POINT](/page/Entry_point) INTEGER. These declarations can include additional attributes like storage class (e.g., STATIC for fixed memory allocation or BASED for dynamic addressing). Scope is primarily block-level, meaning declarations are visible only within the enclosing block (delimited by structures like BLOCK or PROCEDURE), but qualifiers such as GLOBAL or EXTERNAL extend visibility across blocks or programs, enabling shared access in multi-module setups. For example, DECLARE VAR GLOBAL INTEGER makes VAR accessible throughout the program.[5]
Undeclared identifiers trigger compile-time errors, as the compiler requires all variables and functions to be defined with a mode and storage class before use; failure to do so results in no symbol table entry, leading to diagnostics like "undefined identifier" and potential program rejection. Defaults may apply in some cases (e.g., undeclared variables assuming FLOATING SHORT mode), but explicit declarations are mandatory for correctness and to avoid incomplete type information. This strict enforcement supports robust code verification during compilation.[5]
Executable Statements
Executable statements in the MAD programming language form the core of program execution, enabling assignments, conditional branching, iteration, and unstructured jumps. These statements are processed sequentially unless altered by control mechanisms, with expressions evaluated left-to-right and supporting implicit type conversions during assignments, such as from integer to floating-point.[1] The assignment statement assigns the value of an expression to a variable, using the syntaxvariable = expression. For example, Y = 1 assigns the integer value 1 to the floating-point variable Y, performing automatic conversion. Expressions in assignments may include arithmetic operations and are evaluated without side effects unless involving function calls, though MAD emphasizes deterministic evaluation to avoid unintended behaviors.[1]
Conditional execution is handled primarily through the WHENEVER statement, which executes an associated statement if a boolean expression evaluates to true. The simple form is WHENEVER boolean_expression, statement, such as WHENEVER X .LE. 0, TRANSFER TO END, which jumps to a label if X is less than or equal to zero. For multi-way branching, compound conditionals use WHENEVER B1, S1 OR WHENEVER B2, S2 ... END OF CONDITIONAL, executing the first true branch and skipping others; an example is WHENEVER X .LE. 0, Y = 0 OR WHENEVER X .GE. 3, Y = 1 END OF CONDITIONAL. These structures promote readable control flow while allowing ELSE-like behavior via an OTHERWISE clause in extended forms.[1][24]
Iteration is achieved using the THROUGH statement combined with FOR, defining a loop scope from the THROUGH to a labeled endpoint. The syntax is THROUGH label, FOR variable = start, increment, boolean_condition, repeating the enclosed statements until the condition holds; for instance, THROUGH BACK, FOR J = 1, 1, J .G. N iterates J from 1 to N in steps of 1, executing code until J > N, then continuing at the BACK label. This design integrates loop control with statement labeling, supporting nested iterations without explicit DO keywords.[1][25]
Unstructured control transfer is provided by TRANSFER TO label, enabling jumps to any labeled statement for flexibility in early algorithmic coding, though MAD documentation encourages structured alternatives like WHENEVER and THROUGH to minimize reliance on GOTOs. Labels are defined by placing them before statements, such as SUMX: Z = A + B.[1]
To group multiple statements into a compound unit, MAD uses BEGIN-END blocks, which delimit scopes for conditionals, loops, or sequences, supporting lexical scoping and recursion as in ALGOL influences. An example is BEGIN X = 1; Y = X + 2 END, treating the enclosed assignments as a single executable unit. This facilitates modular execution without unstructured jumps, aligning with MAD's emphasis on algorithmic clarity.[24][1]
Input Output and Functions
Input and Output Statements
In the MAD programming language, output operations are primarily handled through the PRINT statement, which directs data to printers or other output devices according to predefined formats. The basic syntax isPRINT FORMAT J, A, where J is the name of a format vector and A is a list of variables or expressions to be printed. For instance, PRINT RESULTS A, X, EPS outputs the values of variables A, X, and EPS using the format specified in RESULTS. Formats themselves are defined using vector declarations enclosed in dollar-sign delimiters, such as VECTOR VALUES RESULT = $9H(C MATRIX//1H0,8F13.4)*$, which specifies a layout including Hollerith constants for labels and floating-point fields.[1]
Input operations utilize the READ statement, which retrieves data from input sources like punched cards or files into specified variables. The syntax mirrors output with READ FORMAT J, A, reading values into list A based on format J; a simplified form READ DATA processes cards containing variable-value pairs until an end marker like /- is encountered. For example, READ FORMAT $3F10.4*$ A, B, C inputs three floating-point numbers with 10-character fields and 4 decimal places each from sequential cards, scanning left-to-right. This supports batch processing from card decks or tape files, with the compiler handling device-specific details.[1]
Format specifications in MAD consist of a sequence of field descriptors, each indicating data type, width, and precision, terminated by an asterisk within the dollar delimiters. Common descriptors include I for integers (e.g., I2 for a 2-column field), F for fixed-point decimals (e.g., F10.3 for 10 columns with 3 decimals), E for scientific notation (e.g., E22.9), K for octal constants, and C for characters. Hollerith notation embeds fixed strings, such as 6HBETA = for a 6-character label followed by an equal sign, while S skips columns (e.g., S16 for 16 spaces). Hexadecimal field lengths are supported via modifiers like B for base specification, as in 16BI12 for a 12-digit hexadecimal integer, allowing precise control over non-decimal outputs. Additional features include scale factors with E, right-justification with R, and zero-filling with Z.[1]
The GOM variant of MAD, a reimplementation for IBM System/360 and 370 architectures, enhances input and output with improved string handling and more flexible format specifications. While retaining core PRINT and READ syntax, GOM introduces refined hexadecimal notation for field lengths to better accommodate varying data sizes and extends string processing for embedded Hollerith fields, reducing parsing overhead in large-scale scientific applications. These changes, detailed in the GOM manual, facilitate porting legacy MAD code while optimizing for modern hardware I/O channels.[10]
Function Definitions
In the MAD programming language, user-defined functions are created to encapsulate reusable computations, supporting both internal and external definitions to facilitate modular programming. Internal functions are defined within the main program body and share the program's variable scope unless specified otherwise, while external functions are defined in separate compilation units for independent translation and linkage.[1] The syntax for defining an internal function begins withINTERNAL FUNCTION followed by the function name (1-6 characters ending in a period), a parameter list in parentheses, and either a single expression assignment or a block of statements. For a single-statement definition, the form is INTERNAL FUNCTION name.(param1, param2, ...) = expression;, where the expression's value implicitly serves as the return value. For multi-statement definitions, the body follows after the parameter list, enclosed implicitly by subsequent statements until the end of the function, with an explicit return via FUNCTION RETURN expression;. An example of a single-statement internal function is INTERNAL FUNCTION SUMSQ.(X, Y, Z) = X*X + Y*Y + Z*Z - T*T;, which computes the sum of squares adjusted by a global variable T. External functions use EXTERNAL FUNCTION name.(param1, param2, ...) followed by declarations (e.g., INTEGER J, N) and a sequence of executable statements, terminated by END OF FUNCTION. A representative external function for finding the maximum in an array is EXTERNAL FUNCTION MAX.(N, A) INTEGER J, N Z = A(0) THROUGH BACK, FOR J = 1, 1, J .G. N BACK WHENEVER Z .L. A(J), Z = A(J) FUNCTION RETURN Z END OF FUNCTION;.[1]
Parameters in MAD functions are specified as dummy variables in the parameter list and are typed through mode declarations such as INTEGER, FLOATING POINT, BOOLEAN, or SWITCH preceding the variable names, with floating-point as the default mode if undeclared. Arguments are passed to these dummies during invocation, where scalars are passed by value (copying the argument's value) and arrays by reference (allowing in-place modifications), ensuring type compatibility between actual arguments and dummies without runtime checks by the compiler. For instance, in the MAX function, the array A is passed by reference, enabling updates to its elements if needed within the function body. Functions support recursion, with temporary storage managed via SAVE DATA and RESTORE DATA statements to preserve state across calls.[1]
Functions are invoked by placing the name followed by actual arguments in parentheses within an expression, such as result = MAX.(6, [Q](/page/Q));, where the returned value replaces the call and can be assigned to a variable or used in further computations. For procedures (void functions), invocation uses EXECUTE name.(args); as a standalone statement. The return value's mode must align with the function's implicit or declared mode, explicitly provided via FUNCTION RETURN expression; at the desired exit point, or implicitly via the last expression in single-statement forms; an ERROR RETURN variant handles exceptions by transferring control to a specified label. Invocation integrates seamlessly into executable statements, enhancing code modularity without altering the main program's flow.[1]
MAD provides a limited set of built-in functions, such as COS., SIN., and ELOG. for trigonometric and logarithmic operations, which follow the same invocation syntax as user-defined functions but cannot be redefined directly. These built-ins establish foundational mathematical capabilities, with extensibility achieved through user-defined alternatives where needed.[1]
Extensibility Features
Operator Definition and Redefinition
MAD's extensibility allows programmers to define new operators or redefine existing ones for specific data modes, enabling the creation of domain-specific notations that integrate seamlessly into expressions. This feature, introduced in early versions of the language, permits users to extend the operator set beyond built-ins, such as arithmetic operators, by specifying custom behaviors through assembly-like instruction sequences.[26][1] The primary mechanism for operator definition involves theDEFINE statement, which declares unary or binary operators with user-specified precedence relative to existing operators. For a binary operator, the syntax is DEFINE BINARY OPERATOR <operator>, PRECEDENCE <SAME AS | LOWER THAN | HIGHER THAN> <existing operator>, where <operator> is typically an extended symbol enclosed in periods (e.g., .EV.), limited to six alphabetic characters. Precedence is assigned hierarchically; for instance, built-in operators like addition (+) have lower precedence than multiplication (*), allowing new operators to be positioned accordingly using relational comparisons. Once defined, the operator's implementation is specified per data mode using MODE STRUCTURE <mode> = <left mode> <operator> <right mode>, followed by a defining sequence of machine instructions written in mnemonic form without location fields. These sequences utilize pseudo-instructions like JMP for control flow, OUT to terminate interpretation, and temporary storage locations such as T (single cell) or DT (double cell). Operators must be defined in lexicographic order before their first use.[26][1]
Redefinition of built-in operators is supported for specific modes without altering their global precedence, allowing customized behaviors for user-defined data types. For example, an existing operator like .P. (exponentiation) can be redefined for mode 6 (a custom floating-point mode) by providing a new instruction sequence, while retaining the original for other modes. This is achieved by reissuing the MODE STRUCTURE statement for the target mode, optionally referencing prior sequences with SAME SEQUENCE AS to reuse code. Such redefinitions enable overriding built-in semantics in domain-specific contexts, like optimizing operations for specialized numeric types.[26][1]
A representative example is defining a new infix operator .EV. for bitwise exclusive-or on integers (mode 1), which integrates into arithmetic expressions:
DEFINE BINARY OPERATOR .EV., PRECEDENCE SAME AS .V.
MODE [STRUCTURE](/page/Structure) 1 = 1 .EV. 1
CLA A1 /* Clear accumulator, load left [operand](/page/Operand) */
TSX T /* Transfer to temporary */
CLA A2 /* Load right [operand](/page/Operand) */
ANA T /* Logical AND with temporary (for XOR simulation) */
STA TEMP /* Store intermediate */
... /* Additional instructions for full XOR */
OUT /* End sequence */
END /* End [definition](/page/Definition) */
DEFINE BINARY OPERATOR .EV., PRECEDENCE SAME AS .V.
MODE [STRUCTURE](/page/Structure) 1 = 1 .EV. 1
CLA A1 /* Clear accumulator, load left [operand](/page/Operand) */
TSX T /* Transfer to temporary */
CLA A2 /* Load right [operand](/page/Operand) */
ANA T /* Logical AND with temporary (for XOR simulation) */
STA TEMP /* Store intermediate */
... /* Additional instructions for full XOR */
OUT /* End sequence */
END /* End [definition](/page/Definition) */
X .EV. Y in expressions, mimicking built-in bitwise operations but with custom assembly for efficiency. Another example redefines multiplication for double-precision mode 5 by calling a subroutine DPM:
MODE [STRUCTURE](/page/Structure) 5 = 5 * 5
TSX DPM /* Transfer to double-precision multiply subroutine */
OUT
END
MODE [STRUCTURE](/page/Structure) 5 = 5 * 5
TSX DPM /* Transfer to double-precision multiply subroutine */
OUT
END
Built-in Packages
MAD's built-in packages provide predefined extensions for advanced numerical computations, allowing programmers to incorporate specialized types, operators, and functions without manual implementation. These packages are included in a program using theINCLUDE statement (abbreviated as I'E), which loads definitions from secondary storage into the source code.[1] The three primary built-in packages—MATRIX, DOUBLE PRECISION, and COMPLEX—address common needs in scientific and engineering applications, extending the language's core capabilities for matrices, high-precision arithmetic, and complex numbers.[1][26]
The MATRIX package enables vector and matrix arithmetic, introducing matrix variables as a specialized type built on two-dimensional arrays (e.g., declared as MATRIX A(10,10)). Upon inclusion, it adds operators for matrix addition, subtraction, multiplication, and transposition, along with built-in functions such as DET for computing the determinant and INVERSE for matrix inversion.[1] These features simplify linear algebra tasks, such as solving systems of equations, by treating matrices as first-class objects with dedicated syntax (e.g., C = A * B for matrix multiplication). Arrays in general benefit from MATRIX by gaining support for higher-dimensional operations when matrix types are activated.[1]
The DOUBLE PRECISION package supports extended floating-point arithmetic through mode 5 declarations, doubling the storage precision for numeric variables (e.g., DOUBLE PRECISION X). It introduces a binary multiplication operator (*) implemented via a subroutine (DPM) that operates on accumulator (AC) and multiplier-quotient (MQ) registers, ensuring accurate computations for applications requiring more than single-precision resolution.[26] This package effectively extends the language's numeric modes (0-7) by allocating additional storage, as in DOUBLE STORAGE MODE 5.[1]
The COMPLEX package facilitates handling of imaginary and complex numbers using modes 6 and 7, allowing declarations like COMPLEX Z. It adds arithmetic operators for complex addition, subtraction, multiplication, and division, treating complex values as pairs of real and imaginary components.[1] Inclusion activates these modes and associated functions, enabling computations in fields like electrical engineering and physics without custom subroutines.[26]
These built-in packages are implemented at an assembly level using MAD's definition facility, which compiles user-like definitions into machine instructions for efficiency.[26] They are user-extensible, as programmers can create and include custom packages following the same INCLUDE mechanism, building on the predefined ones for further specialization.[26] Limitations include fixed operator precedence in certain implementations (e.g., IBM 7090 MAD), preventing redefinition of unary/binary symbols or subscription operations due to parsing constraints.[26]References
- https://commons.wikimedia.org/wiki/File:MAD-alfie-1960.jpg
