Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Modula-2 Multi-Pass Compiler (m2cmp)

A self-hosted, 4-pass Modula-2 compiler targeting the Lilith computer's M-code instruction set, originally developed at ETH Zurich (~1981–1982). The compiler is written entirely in Modula-2.


Table of Contents

  1. Architecture Overview
  2. Compilation Pipeline
  3. Pass 1 — Lexical & Syntax Analysis
  4. Pass 2 — Declaration Analysis
  5. Pass 3 — Body / Semantic Analysis
  6. Pass 4 — Code Generation
  7. Core Data Structures
  8. Symbol File System
  9. M-Code Instruction Set
  10. Error Handling Strategy
  11. Module Index
  12. Compiler Limits & Restrictions

Architecture Overview

The compiler follows a classic multi-pass design where each pass reads output produced by the previous one. This separation keeps each pass simple, focused, and independently testable.

Source (.MOD / .DEF)
│
▼
┌───────────────────┐
│ Pass 1 │ Lexical scanning + recursive-descent parsing
│ MCP1MAIN.MOD │──► IL1 file (token stream)
│ │──► ASCII file (identifier spellings)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 2 │ Symbol-table construction + type system
│ MCP2MAIN.MOD │──► IL2 file (type-annotated IL1)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 3 │ Semantic checking + expression analysis
│ MCP3MAIN.MOD │──► IL1 (rewritten, fully resolved)
└───────────────────┘
│
▼
┌───────────────────┐
│ Pass 4 │ M-code generation
│ MCP4MAIN.MOD │──► OBJ file (M-code + relocation)
│ │──► REF file (debug info)
└───────────────────┘
│
▼
.SYM .OBJ .REF .LST

The MCBase module coordinates pass scheduling and maintains the global compilation state (compstat). Each pass is launched as a separate run of the compiler binary with a different pass selector.


Compilation Pipeline

StageMain ModuleReadsWrites
Pass 1MCP1MAIN.MODSource (.MOD)IL1, ASCII
Pass 2MCP2MAIN.MODIL1, ASCIIIL2
Pass 3MCP3MAIN.MODIL1, IL2IL1 (rewritten)
Pass 4MCP4MAIN.MODIL1, IL2OBJ, REF

Pass 1 — Lexical & Syntax Analysis

Entry point:MCP1MAIN.MOD

Responsibilities

  • Scans source characters and produces a token stream.
  • Parses the full Modula-2 grammar using recursive descent.
  • Resolves keywords and identifiers via hash tables.
  • Writes the IL1 interpass file and the ASCII identifier pool.

Key Modules

ModuleRole
MCP1IOCharacter-level input; GetSy() returns the next symbol; HashIdent() maps names to spelling indices (Spellix).
MCP1IdenInitIdTables() populates hash tables with Modula-2 reserved words and predefined identifiers.
MCP1REALParses and stores floating-point literal constants.

Parsing Strategy

The parser uses symbol-set-based error recovery: every grammar rule receives a fsys (follow set) parameter expressed as a BITSET. On an unexpected token the parser emits an error, skips tokens until a member of fsys ∪ first_set is found, and resumes normally. This allows compilation to continue despite syntax errors.

Symset operations
Set1(sy), Set2(sy1,sy2), Set3(sy1,sy2,sy3) — construct sets
InSet(sy, s) — fast membership test
AddSet, SubSet, InclSet — set arithmetic

Grammar Highlights

ConstructNotes
Definition moduleDEFINITION MODULEEND; exports list.
ImplementationIMPLEMENTATION MODULEEND.
BlockType / const / var / proc declarations + statement sequence.
TypesSimple (ident, subrange, enum), Array, Record, Set, Pointer, Procedure.
ExpressionsFull precedence hierarchy; set constructors {a, b..c}.
StatementsIF/ELSIF/ELSE, LOOP/EXIT, WHILE, REPEAT, FOR, CASE, WITH, assignment, call.
CODE proceduresInline octal constants (0..377B) for machine code blocks.

IL1 File Content

A compact binary token stream containing:

  • Symbol kinds (sy field)
  • Spelling indices (spix) for identifiers
  • Literal values (integers, reals, strings, sets)
  • Structural markers (endblock, module/procedure boundaries)

Pass 2 — Declaration Analysis

Entry point:MCP2MAIN.MOD

Responsibilities

  • Builds the symbol table from declarations.
  • Resolves types and checks type consistency.
  • Handles separate compilation (reads/writes .SYM symbol files).
  • Produces the IL2 file — IL1 annotated with type and identifier pointers.

Key Modules

ModuleRole
MCP2IOGetSy() reads IL1; PutSy() / PutWord() write IL2; skip helpers skip over unknown structures.
MCP2IDENScope management: MarkScope / ReleaseScope; SearchId / SearchInBlock / ExportSearch; MsEntry registers items in module scope list.
MCP2REFEForward-reference tracking across modules: Reference(), EndReference().
MCSYMFILSymbol file serialization / deserialization for separate compilation.

Symbol Table Entry — Identrec

Identrec
name : Spellix (* index into ASCII pool *)
link : Idptr (* next in chain *)
klass : Idclass (* const | type | var | field | pure | func | mod | … *)
globmodp : Idptr (* enclosing global module *)
CASE klass OF
consts : cvalue: Constval; idtyp: Stptr
types : idtyp: Stptr
vars : vaddr, vlevel; vkind: Varkind; state: Kindvar
fields : fldaddr: CARDINAL
pures/
funcs : procnum, plev, varlength, locp: Idptr
+ isstandard, codeproc, codeentry/codelength
mods : impp, expp (import/export lists)
+ modulekey[0..2]: CARDINAL (* version tracking *)
END

Type Structure — Structrec

Structrec
form : Structform (* enums | bools | chars | ints | cards | words |
subranges | reals | pointers | sets |
proctypes | arrays | records | hides | opens *)
size : CARDINAL (* size in target words *)
stidp: Idptr (* defining identifier *)
CASE form OF
arrays : elp (element type), ixp (index type), dyn (dynamic?)
records : fieldp (field list), tagp (variant tag)
proctypes : fstparam (parameter list), rkind, funcp (return type)
pointers : elemp (pointed-to type)
sets : basep (base type)
subranges : scalp (base scalar), min, max
enums : fcstp (first constant), cstnr (count)
END

Scope Management

Scopes are maintained as a stack. Each scope corresponds to a procedure or module body:

MarkScope(id) — push new scope
ReleaseScope — pop scope, resolve pending forward references
SearchId(name) — linear search from innermost scope outward

Constant Evaluation

ConstantVal() evaluates constant expressions at compile time using recursive descent. It supports all Modula-2 constant operators, overflow detection, and type compatibility rules (intcar compatibility).

Module Keys

Each compiled definition module receives a 3-word key (modulekey[0..2]). Implementation modules verify their keys match; a mismatch prevents compilation.


Pass 3 — Body / Semantic Analysis

Entry point:MCP3MAIN.MOD

Responsibilities

  • Validates all executable code for semantic correctness.
  • Type-checks expressions, assignments, and procedure calls.
  • Rewrites the IL1 file with fully resolved references for Pass 4.

Key Modules

ModuleRole
MCP3IOReads IL1 + IL2; writes resolved IL1. InitSave/ResetSave/ReleaseSave optimize output buffering.
MCP3IDENScope tracking for bodies: MarkProcScope/ReleaseProcScope, MarkWithScope/ReleaseWithScope, FieldIndex.

Expression System

Attribut = RECORD
mode : Attributmode (* const | var | expr *)
atp : Stptr (* type of expression *)
aval : Constval (* value, if mode = const *)
END

Expression analysis functions:

FunctionDescription
Expression()Full expression (relational operators)
SimpleExpression()Additive / unary operators
Term()Multiplicative operators
Factor()Literals, variables, function calls, (expr)
Selector()[], ., ^
SetConstructor(){a, b..c}

Standard Functions & Procedures

IdentifierCategory
HIGH, SIZE, TSIZE, ADRIntrinsic queries
ODD, ABS, CAPScalar operations
FLOAT, TRUNC, ORD, CHR, VALType conversions
INC, DECIn-place increment / decrement
NEW, DISPOSEDynamic allocation
INCL, EXCLSet mutation
NEWPROCESS, TRANSFERCoroutine support
HALTAbnormal termination

Type Compatibility Rules

CheckFunctionUsed for
Expression compatExprComp()Operands of binary operators
Assignment compatAssignComp()Right-hand side vs. variable type
ADDRESS compatAddressComp()Pointer / ADDRESS coercions
Parameter compatParamCheck()Actual vs. formal parameters
Variant analysisVariantAnalyse()Record variant sizing

Pass 4 — Code Generation

Entry point:MCP4MAIN.MOD

Responsibilities

  • Translates the semantically validated IR into M-code for the Lilith virtual machine.
  • Manages the expression stack, load modes, and address modes.
  • Applies optional range checking and arithmetic overflow checking.
  • Emits OBJ (relocatable M-code) and REF (debug information) files.

Key Modules

ModuleRole
MCP4GLOBGlobal state: loadAddress, level, loadCount, spPosition, blockNptr.
MCP4ATTRAttribute system; load/store code generation; Load(), LoadAddr(), Store(), Assign().
MCP4CODELow-level emitter: Emit(), Emit2(), jump patching (MarkShort/UpdateShort, MarkLong/UpdateLong), string literals, block entry/return.
MCP4EXPRDesignator(), Expression(), ExpressionAndLoad(); WITH-statement scope.
MCP4CALLProcFuncCall() — complete call-site code generation.

Address Modes — AtMode

globalMod — global variable
localMod — local / parameter variable
loadedMod — value already on evaluation stack
addrLoadedMod — address already on evaluation stack
externalMod — imported variable
indexMod — array element (word-indexed)
byteIndexMod — array element (byte-indexed)
doubleIndexMod — array element (double-word-indexed)
absolutMod — absolute address
constantMod — compile-time constant (single word)
doubleConstMod — compile-time constant (double word / REAL)
stringConstMod — string literal
procedureMod — procedure value
illegalMod — error sentinel

Statement Code Generation

StatementCode pattern
AssignmentEvaluate RHS → Load()Store() to LHS
IFEvaluate condition → conditional forward jump; patch on END
CASEENTC/EXC jump table; dense packing; range check if enabled
LOOPSave loop PC; EXIT generates forward jump patched at END LOOP
WHILEConditional forward jump over body + unconditional backward jump
REPEATBody then conditional backward jump
FORFOR1 (init) + FOR2 (step+test); handles positive/negative step
WITHEnterWith() saves record address; body; ExitWith() restores
RETURNLoad return value (functions) → GenBlockReturn()

Jump Optimization

Backward branch distance is estimated before emission:

  • Short jump (JPB): 1-byte signed offset, range −256 … +256.
  • Long jump (JP): 2-word full address.

If the estimate is wrong the emitter iterates until stable.


Core Data Structures

Constval — Compile-Time Value

Constval = RECORD
CASE str: Structform OF
arrays : svalue: Stringptr (* string constant *)
|reals : rvalue: POINTER TO REAL (* double-precision float *)
ELSE
value : CARDINAL (* integer / boolean / char / set *)
END
END

Idclass — Identifier Classification

Idclass = { consts, types, vars, fields, pures, funcs,
mods, unknown, indrct }

Varkind — Parameter Passing Convention

Varkind = { noparam, valparam, varparam, copyparam }

Kindvar — Variable Storage Class

Kindvar = { global, local, absolute, separate }

Symbol File System

Symbol files (.SYM) enable separate compilation: a definition module is compiled once and its type information is saved; implementation modules or client modules read it back without re-parsing the source.

Symbol File Symbols (SymFileSymbols)

endfileSS, unitSS, endunitSS,
importSS, exportSS,
constSS, normalconstSS, realconstSS, stringconstSS,
typSS, arraytypSS, recordtypSS, settypSS, pointertypSS, hiddentypSS,
varSS, procSS, funcSS,
identSS,
periodSS, colonSS, rangeSS,
lparentSS, rparentSS, lbracketSS, rbracketSS,
caseSS, ofSS, elseSS, endSS

Module keys (modulekey[0..2]: CARDINAL) guard against stale symbol files: any mismatch between the stored key and the current compilation aborts with a symbol error (symerrs).


M-Code Instruction Set

Selected instructions generated by Pass 4 (see MCMNEMON.DEF for full list):

CategoryMnemonics
LoadLI (immediate), LLW (local word), LGW (global word), LSW (stack-relative)
StoreSTORE, SLW (store local), SGW (store global)
ArithmeticADD, SUB, MUL, DIVV, MOD, SHL, SHR
LogicANDD, ORR, XORR, NOTT, INN (set membership)
ComparisonEQL, NEQ, LSS, LEQ, GTR, GEQ
JumpJP (unconditional), JPFC (jump-on-false), JPB (backward)
Block memoryMOV, BBLT (block move)
ProceduresENTR (entry), RTN (return), CL (call)
LoopFOR1 (loop init), FOR2 (loop step + test)
CaseENTC (case entry), EXC (case exit)
RuntimeTRAP (runtime check), CHKS (range check)

Error Handling Strategy

FlagMeaningEffect
globerrsUnrecoverable global errorStop entire compilation
passerrsError in current passReport and proceed to next pass
symerrsSymbol file inconsistencyBlock dependent passes

Each pass contributes distinct error categories:

  • Pass 1: Unexpected tokens, missing delimiters (recovered via symbol sets).
  • Pass 2: Unknown identifiers, type mismatches, scope violations, forward-reference failures.
  • Pass 3: Expression type errors, invalid assignments, bad actual parameters, illegal standard-procedure usage.
  • Pass 4: Range violations (emits CHKS/TRAP if checking enabled); bad code structure.

Module Index

Compiler Passes

FileDescription
MCP1MAIN.MODPass 1 top-level: scanner + recursive-descent parser
MCP2MAIN.MODPass 2 top-level: declaration analysis + symbol table
MCP3MAIN.MODPass 3 top-level: body analysis + semantic checks
MCP4MAIN.MODPass 4 top-level: M-code emission

Pass 1 Support

FileDescription
MCP1IO.DEF/MODLexical I/O, symbol reading, identifier hashing
MCP1Iden.DEF/MODKeyword and identifier table initialisation
MCP1REAL.DEF/MODFloating-point literal parsing

Pass 2 Support

FileDescription
MCP2IO.DEF/MODIL1 reader + IL2 writer
MCP2IDEN.DEF/MODScope stack, identifier search, scope mark/release
MCP2REFE.DEF/MODCross-module forward-reference tracking

Pass 3 Support

FileDescription
MCP3IO.DEF/MODIL reader/writer with save-point optimisation
MCP3IDEN.DEF/MODBody-level scope (proc, module, WITH scopes)

Pass 4 Support

FileDescription
MCP4GLOB.DEF/MODGlobal state variables for code generation
MCP4ATTR.DEF/MODAttribute / address-mode system; load/store helpers
MCP4CODE.DEF/MODLow-level instruction emitter; jump patching; string pool
MCP4EXPR.DEF/MODExpression + designator code generation
MCP4CALL.DEF/MODProcedure / function call code generation

Shared Infrastructure

FileDescription
MCBASE.DEF/MODCore type definitions (Identrec, Structrec, Constval); pass coordinator
MCPUBLIC.DEF/MODCompilation status flags; interpass file handles
MCSYMFIL.DEF/MODSymbol file read/write for separate compilation
MCSYM.MODSymbol table utilities
MCOPERAT.DEF/MODOperator encoding / decoding
MCMNEMON.DEF/MODM-code mnemonic definitions
MCFILENA.DEF/MODFile name construction helpers
MCINIT.MODModule initialisation sequencing
MCQLIST.MODQueue-list utilities
MCLIST.MODLinked-list utilities
CONVERSI.DEF/MODNumeric conversion routines
DECODE.MODM-code disassembler / decoder
DECOMACH.DEF/MODDecoding machine support
OPTIONS.DEF/MODCompiler command-line option parsing
NEWSTREA.DEF/MODStream I/O abstraction
WRITESTR.DEF/MODString output utilities
FILELOOK.DEF/MODFile lookup / search path resolution
FILENAME.DEF/MODFile name manipulation
FILEPOOL.DEF/MODFile handle pool management
parser.modStandalone parser module

Documentation & Grammar

FileDescription
GS-M2.bnfBNF grammar for Modula-2 as accepted by this compiler
MODNOTES.TXTDevelopment notes
INTERP.DOCInterpreter / M-code documentation
M2M-PC.DOCM2M PC-port documentation
COMP.txtCompilation notes

Compiler Limits & Restrictions

ParameterLimit
Maximum nesting level15 (levmax)
Maximum module name24 characters
Maximum module priority15
Module key width3 × CARDINAL
Array index typeCARDINAL range
Real numbersREAL (separate from INTEGER / CARDINAL)
CODE procedure opcode0 … 255 (0..377B)

Supported Language Features

  • Separate compilation (.DEF + .MOD pairs)
  • Qualified import / export
  • Variant records (tagged discriminated unions)
  • Dynamic arrays with dimension information (HIGH)
  • Nested procedures and nested modules
  • CODE procedures (inline M-code)
  • Full set of standard functions and procedures
  • Set types with bitwise operations
  • Pointer types with forward references
  • Module initialisation sequences
  • Coroutine support (NEWPROCESS, TRANSFER)
  • SYSTEM module integration (ADDRESS, WORD, ADR, TSIZE)

About

Modula-2 Compiler

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages