|
|
@@ -0,0 +1,548 @@
|
|
|
+# Mini Modula-2 Compiler — Explanations
|
|
|
+
|
|
|
+## 1. Goal
|
|
|
+
|
|
|
+The project is a simplified Modula-2-like compiler implemented in GNU Modula-2.
|
|
|
+
|
|
|
+The language is intentionally smaller than full Modula-2:
|
|
|
+
|
|
|
+- no procedures or functions
|
|
|
+- `INTEGER` and `CHAR` types
|
|
|
+- variables and constants as supported by the compiler
|
|
|
+- basic statements and expressions
|
|
|
+- symbol table
|
|
|
+- type checking
|
|
|
+- code generation
|
|
|
+
|
|
|
+The objective is to have a real compiler pipeline rather than only a parser.
|
|
|
+
|
|
|
+## 2. Compiler architecture
|
|
|
+
|
|
|
+The compiler follows this pipeline:
|
|
|
+
|
|
|
+```text
|
|
|
+MiniM2 source
|
|
|
+ |
|
|
|
+ v
|
|
|
++-----------+
|
|
|
+| Lexer |
|
|
|
++-----------+
|
|
|
+ |
|
|
|
+ v
|
|
|
++-----------+
|
|
|
+| Parser |
|
|
|
++-----------+
|
|
|
+ |
|
|
|
+ v
|
|
|
++----------------+
|
|
|
+| Symbol table |
|
|
|
+| Type checking |
|
|
|
++----------------+
|
|
|
+ |
|
|
|
+ v
|
|
|
++----------------+
|
|
|
+| Code generator |
|
|
|
++----------------+
|
|
|
+ |
|
|
|
+ v
|
|
|
+Generated GNU Modula-2
|
|
|
+ |
|
|
|
+ v
|
|
|
++-----------+
|
|
|
+| gm2 |
|
|
|
++-----------+
|
|
|
+ |
|
|
|
+ v
|
|
|
+Native executable
|
|
|
+```
|
|
|
+
|
|
|
+The compiler itself is written in GNU Modula-2.
|
|
|
+
|
|
|
+## 3. Why GNU Modula-2 is used as the backend
|
|
|
+
|
|
|
+Coco/R has traditionally provided compiler-generator targets such as C#, Java and C++, but GNU Modula-2 is not a standard Coco/R target.
|
|
|
+
|
|
|
+Instead of trying to make Coco/R generate GNU Modula-2 code, the compiler can be implemented directly in GNU Modula-2.
|
|
|
+
|
|
|
+The first native backend is source-to-source:
|
|
|
+
|
|
|
+1. Parse the MiniM2 program.
|
|
|
+2. Build and check its symbols and types.
|
|
|
+3. Generate valid GNU Modula-2.
|
|
|
+4. Invoke `gm2`.
|
|
|
+5. Let GNU Modula-2 produce the final native executable.
|
|
|
+
|
|
|
+This is already a genuine compiler architecture: the front-end performs lexical analysis, parsing and semantic checking, while GNU Modula-2 acts as the native backend.
|
|
|
+
|
|
|
+## 4. GNU Modula-2
|
|
|
+
|
|
|
+GNU Modula-2 is provided by GCC.
|
|
|
+
|
|
|
+Typical compilation is:
|
|
|
+
|
|
|
+```bash
|
|
|
+gm2 -g hello.mod
|
|
|
+```
|
|
|
+
|
|
|
+GNU Modula-2 uses `.mod` files for implementation/program modules and `.def` files for definition modules.
|
|
|
+
|
|
|
+The generated program can therefore be compiled by the GNU Modula-2 compiler.
|
|
|
+
|
|
|
+## 5. Project layout
|
|
|
+
|
|
|
+The generated project is:
|
|
|
+
|
|
|
+```text
|
|
|
+mini-modula2-real-compiler/
|
|
|
+├── MiniM2C.mod
|
|
|
+├── Makefile
|
|
|
+├── README.md
|
|
|
+└── examples/
|
|
|
+ ├── hello.mod
|
|
|
+ └── bad.mod
|
|
|
+```
|
|
|
+
|
|
|
+`MiniM2C.mod` contains the compiler implementation.
|
|
|
+
|
|
|
+`examples/hello.mod` is a valid example program.
|
|
|
+
|
|
|
+`examples/bad.mod` is intended to demonstrate semantic/type errors.
|
|
|
+
|
|
|
+## 6. Building
|
|
|
+
|
|
|
+From the project directory:
|
|
|
+
|
|
|
+```bash
|
|
|
+make
|
|
|
+```
|
|
|
+
|
|
|
+The compiler executable is intended to be:
|
|
|
+
|
|
|
+```text
|
|
|
+minim2c
|
|
|
+```
|
|
|
+
|
|
|
+A MiniM2 source file can then be compiled with:
|
|
|
+
|
|
|
+```bash
|
|
|
+./minim2c examples/hello.mod
|
|
|
+```
|
|
|
+
|
|
|
+The compiler generates a GNU Modula-2 source file:
|
|
|
+
|
|
|
+```text
|
|
|
+examples/hello.mod.gen.mod
|
|
|
+```
|
|
|
+
|
|
|
+and then invokes `gm2` to build the native executable.
|
|
|
+
|
|
|
+The exact executable name can depend on the generated module and GNU Modula-2 toolchain.
|
|
|
+
|
|
|
+## 7. Running the example
|
|
|
+
|
|
|
+The intended workflow is:
|
|
|
+
|
|
|
+```bash
|
|
|
+cd mini-modula2-real-compiler
|
|
|
+make
|
|
|
+./minim2c examples/hello.mod
|
|
|
+./mini-program
|
|
|
+```
|
|
|
+
|
|
|
+If the generated executable has a different name, use the executable name reported by the compiler or inspect the generated build output.
|
|
|
+
|
|
|
+## 8. Lexer
|
|
|
+
|
|
|
+The lexer converts source characters into tokens.
|
|
|
+
|
|
|
+Typical token categories include:
|
|
|
+
|
|
|
+- identifiers
|
|
|
+- integer literals
|
|
|
+- character literals
|
|
|
+- operators
|
|
|
+- punctuation
|
|
|
+- keywords
|
|
|
+
|
|
|
+Examples of keywords include:
|
|
|
+
|
|
|
+```text
|
|
|
+MODULE
|
|
|
+BEGIN
|
|
|
+END
|
|
|
+VAR
|
|
|
+CONST
|
|
|
+INTEGER
|
|
|
+CHAR
|
|
|
+READ
|
|
|
+WRITE
|
|
|
+IF
|
|
|
+THEN
|
|
|
+ELSE
|
|
|
+WHILE
|
|
|
+DO
|
|
|
+```
|
|
|
+
|
|
|
+The lexer is responsible for recognizing these tokens before parsing.
|
|
|
+
|
|
|
+## 9. Parser
|
|
|
+
|
|
|
+The parser consumes the token stream and verifies that the program follows the MiniM2 grammar.
|
|
|
+
|
|
|
+A simplified structure is:
|
|
|
+
|
|
|
+```text
|
|
|
+Module
|
|
|
+ = MODULE identifier ;
|
|
|
+ declarations
|
|
|
+ BEGIN
|
|
|
+ statements
|
|
|
+ END identifier .
|
|
|
+```
|
|
|
+
|
|
|
+Expressions are parsed according to precedence.
|
|
|
+
|
|
|
+For example:
|
|
|
+
|
|
|
+```text
|
|
|
+a + b * c
|
|
|
+```
|
|
|
+
|
|
|
+must be interpreted as:
|
|
|
+
|
|
|
+```text
|
|
|
+a + (b * c)
|
|
|
+```
|
|
|
+
|
|
|
+rather than:
|
|
|
+
|
|
|
+```text
|
|
|
+(a + b) * c
|
|
|
+```
|
|
|
+
|
|
|
+## 10. Symbol table
|
|
|
+
|
|
|
+The symbol table records declared identifiers.
|
|
|
+
|
|
|
+For each identifier the compiler can keep information such as:
|
|
|
+
|
|
|
+```text
|
|
|
+name
|
|
|
+kind
|
|
|
+type
|
|
|
+```
|
|
|
+
|
|
|
+For example:
|
|
|
+
|
|
|
+```text
|
|
|
+x : INTEGER
|
|
|
+letter : CHAR
|
|
|
+```
|
|
|
+
|
|
|
+When an identifier is used, the compiler looks it up in the symbol table.
|
|
|
+
|
|
|
+This allows the compiler to detect errors such as:
|
|
|
+
|
|
|
+```text
|
|
|
+unknown variable
|
|
|
+duplicate declaration
|
|
|
+```
|
|
|
+
|
|
|
+## 11. Type checking
|
|
|
+
|
|
|
+The semantic phase checks that expressions and statements use compatible types.
|
|
|
+
|
|
|
+Examples:
|
|
|
+
|
|
|
+```text
|
|
|
+INTEGER + INTEGER
|
|
|
+```
|
|
|
+
|
|
|
+is valid.
|
|
|
+
|
|
|
+But:
|
|
|
+
|
|
|
+```text
|
|
|
+INTEGER + CHAR
|
|
|
+```
|
|
|
+
|
|
|
+is rejected by the type checker.
|
|
|
+
|
|
|
+Assignments are also checked.
|
|
|
+
|
|
|
+For example:
|
|
|
+
|
|
|
+```text
|
|
|
+VAR
|
|
|
+ x : INTEGER;
|
|
|
+ c : CHAR;
|
|
|
+```
|
|
|
+
|
|
|
+Then:
|
|
|
+
|
|
|
+```text
|
|
|
+x := 10;
|
|
|
+```
|
|
|
+
|
|
|
+is valid, while:
|
|
|
+
|
|
|
+```text
|
|
|
+x := c;
|
|
|
+```
|
|
|
+
|
|
|
+should produce a type error.
|
|
|
+
|
|
|
+## 12. Code generation
|
|
|
+
|
|
|
+The current backend generates GNU Modula-2 source.
|
|
|
+
|
|
|
+For example, an internal MiniM2 construct such as:
|
|
|
+
|
|
|
+```text
|
|
|
+x := 10;
|
|
|
+```
|
|
|
+
|
|
|
+can be emitted as GNU Modula-2:
|
|
|
+
|
|
|
+```modula2
|
|
|
+x := 10;
|
|
|
+```
|
|
|
+
|
|
|
+The generated source is then compiled by `gm2`.
|
|
|
+
|
|
|
+This approach makes the compiler relatively small while still producing native executables.
|
|
|
+
|
|
|
+## 13. Important backend limitation
|
|
|
+
|
|
|
+The first implementation is deliberately simple.
|
|
|
+
|
|
|
+In particular, the initial `WRITE` implementation supports only simple operands such as an identifier or literal rather than every possible expression.
|
|
|
+
|
|
|
+For example, this may be supported:
|
|
|
+
|
|
|
+```text
|
|
|
+WRITE(x);
|
|
|
+```
|
|
|
+
|
|
|
+while something such as:
|
|
|
+
|
|
|
+```text
|
|
|
+WRITE(x + 1);
|
|
|
+```
|
|
|
+
|
|
|
+requires an expression-aware `WRITE` code-generation path.
|
|
|
+
|
|
|
+That is one of the natural next improvements.
|
|
|
+
|
|
|
+## 14. Error handling
|
|
|
+
|
|
|
+The compiler should report lexical, syntactic and semantic errors.
|
|
|
+
|
|
|
+Examples:
|
|
|
+
|
|
|
+```text
|
|
|
+unexpected token
|
|
|
+expected identifier
|
|
|
+undeclared identifier
|
|
|
+duplicate declaration
|
|
|
+type mismatch
|
|
|
+```
|
|
|
+
|
|
|
+A useful future improvement is to preserve exact source line and column information for every token and report errors like:
|
|
|
+
|
|
|
+```text
|
|
|
+example.mod:12:7: type mismatch
|
|
|
+```
|
|
|
+
|
|
|
+## 15. Why this is a real compiler
|
|
|
+
|
|
|
+A compiler does not have to directly emit machine instructions itself.
|
|
|
+
|
|
|
+A common architecture is:
|
|
|
+
|
|
|
+```text
|
|
|
+source
|
|
|
+ -> front-end
|
|
|
+ -> intermediate representation / generated source
|
|
|
+ -> backend compiler
|
|
|
+ -> object code
|
|
|
+ -> executable
|
|
|
+```
|
|
|
+
|
|
|
+In this project, GNU Modula-2 is the backend.
|
|
|
+
|
|
|
+The compiler therefore performs real compilation work:
|
|
|
+
|
|
|
+- lexical analysis
|
|
|
+- syntax analysis
|
|
|
+- symbol resolution
|
|
|
+- semantic/type checking
|
|
|
+- code generation
|
|
|
+- native compilation
|
|
|
+
|
|
|
+## 16. Future evolution
|
|
|
+
|
|
|
+A stronger version can evolve toward:
|
|
|
+
|
|
|
+### AST
|
|
|
+
|
|
|
+Instead of immediately generating code while parsing, build an Abstract Syntax Tree:
|
|
|
+
|
|
|
+```text
|
|
|
+Module
|
|
|
+ ├── Declarations
|
|
|
+ └── Statements
|
|
|
+ ├── Assignment
|
|
|
+ ├── If
|
|
|
+ ├── While
|
|
|
+ └── Write
|
|
|
+```
|
|
|
+
|
|
|
+### Intermediate representation
|
|
|
+
|
|
|
+The AST can then be converted into an IR.
|
|
|
+
|
|
|
+For example:
|
|
|
+
|
|
|
+```text
|
|
|
+LOAD_CONST 10
|
|
|
+STORE x
|
|
|
+```
|
|
|
+
|
|
|
+or:
|
|
|
+
|
|
|
+```text
|
|
|
+LOAD x
|
|
|
+LOAD 1
|
|
|
+ADD
|
|
|
+STORE x
|
|
|
+```
|
|
|
+
|
|
|
+### Better code generation
|
|
|
+
|
|
|
+The IR can then be translated to:
|
|
|
+
|
|
|
+- GNU Modula-2
|
|
|
+- C
|
|
|
+- LLVM IR
|
|
|
+- assembly
|
|
|
+- another native backend
|
|
|
+
|
|
|
+### More language features
|
|
|
+
|
|
|
+Possible additions include:
|
|
|
+
|
|
|
+- `BOOLEAN`
|
|
|
+- arrays
|
|
|
+- records
|
|
|
+- `FOR`
|
|
|
+- richer `IF`
|
|
|
+- richer `WHILE`
|
|
|
+- modules and definition modules
|
|
|
+- procedures
|
|
|
+- functions
|
|
|
+- parameters
|
|
|
+- standard library support
|
|
|
+
|
|
|
+## 17. Relation to the Theia extension
|
|
|
+
|
|
|
+The compiler and the Theia Modula-2 extension can eventually be integrated.
|
|
|
+
|
|
|
+Theia can provide:
|
|
|
+
|
|
|
+- syntax highlighting
|
|
|
+- indentation
|
|
|
+- keyword uppercasing
|
|
|
+- snippets
|
|
|
+- diagnostics
|
|
|
+- build commands
|
|
|
+- compiler invocation
|
|
|
+- error navigation
|
|
|
+
|
|
|
+The compiler can provide:
|
|
|
+
|
|
|
+- parsing
|
|
|
+- semantic analysis
|
|
|
+- type checking
|
|
|
+- code generation
|
|
|
+- executable generation
|
|
|
+
|
|
|
+A future language-server integration could expose compiler diagnostics directly in the editor.
|
|
|
+
|
|
|
+## 18. Automatic keyword uppercasing
|
|
|
+
|
|
|
+The Theia extension has a separate editor feature for automatic Modula-2 keyword uppercasing.
|
|
|
+
|
|
|
+The required behavior is:
|
|
|
+
|
|
|
+> Only the keyword currently being typed is converted to uppercase.
|
|
|
+
|
|
|
+It should not uppercase unrelated existing text in the document.
|
|
|
+
|
|
|
+For example, when typing:
|
|
|
+
|
|
|
+```text
|
|
|
+mod
|
|
|
+```
|
|
|
+
|
|
|
+the editor can turn the current keyword into:
|
|
|
+
|
|
|
+```text
|
|
|
+MOD
|
|
|
+```
|
|
|
+
|
|
|
+without modifying other words.
|
|
|
+
|
|
|
+## 19. Snippets
|
|
|
+
|
|
|
+The Theia extension can also provide Modula-2 snippets.
|
|
|
+
|
|
|
+Typical snippets can accelerate constructs such as:
|
|
|
+
|
|
|
+```modula2
|
|
|
+MODULE ...;
|
|
|
+BEGIN
|
|
|
+...
|
|
|
+END ... .
|
|
|
+```
|
|
|
+
|
|
|
+or declarations and control structures.
|
|
|
+
|
|
|
+Snippets are normally triggered through the editor's completion/snippet mechanism.
|
|
|
+
|
|
|
+## 20. Verification status
|
|
|
+
|
|
|
+The project was generated as a GNU Modula-2 compiler prototype.
|
|
|
+
|
|
|
+It should not be described as production-ready without compiling and testing it with an installed GNU Modula-2 (`gm2`) toolchain.
|
|
|
+
|
|
|
+The development environment used to prepare the project did not have `gm2` available, so the generated compiler was not actually built and executed there.
|
|
|
+
|
|
|
+Before treating it as a finished compiler, install GNU Modula-2 and run:
|
|
|
+
|
|
|
+```bash
|
|
|
+gm2 --version
|
|
|
+make
|
|
|
+./minim2c examples/hello.mod
|
|
|
+```
|
|
|
+
|
|
|
+Then test both successful programs and intentionally invalid programs.
|
|
|
+
|
|
|
+## 21. Recommended next step
|
|
|
+
|
|
|
+The most useful next improvement is to make the compiler robust enough to compile its complete test suite under GNU Modula-2.
|
|
|
+
|
|
|
+After that, the compiler can be upgraded from the simple source-to-source backend to:
|
|
|
+
|
|
|
+```text
|
|
|
+Lexer
|
|
|
+ -> Parser
|
|
|
+ -> AST
|
|
|
+ -> Symbol table
|
|
|
+ -> Type checker
|
|
|
+ -> IR
|
|
|
+ -> Code generator
|
|
|
+ -> Native executable
|
|
|
+```
|
|
|
+
|
|
|
+This provides a cleaner foundation for adding the full set of desired Modula-2 features.
|