1 (* M2RTS.mod Implements the run time system facilities of Modula-2.
3 Copyright (C) 2001-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. *)
27 IMPLEMENTATION MODULE M2RTS ;
30 FROM libc IMPORT abort, exit, write, getenv, printf, strlen ;
31 (* FROM Builtins IMPORT strncmp, strcmp ; not available during bootstrap. *)
32 FROM NumberIO IMPORT CardToStr ;
33 FROM StrLib IMPORT StrCopy, StrLen, StrEqual ;
34 FROM SYSTEM IMPORT ADR ;
35 FROM ASCII IMPORT nl, nul ;
36 FROM Storage IMPORT ALLOCATE ;
46 PtrToChar = POINTER TO CHAR ;
48 ProcedureList = RECORD
49 head, tail: ProcedureChain
52 ProcedureChain = POINTER TO RECORD
55 next: ProcedureChain ;
61 TerminateProc: ProcedureList ;
65 Initialized : BOOLEAN ;
69 ConstructModules - resolve dependencies and then call each
70 module constructor in turn.
73 PROCEDURE ConstructModules (applicationmodule, libname: ADDRESS;
74 overrideliborder: ADDRESS;
75 argc: INTEGER; argv, envp: ADDRESS) ;
77 M2Dependent.ConstructModules (applicationmodule, libname,
80 END ConstructModules ;
84 DeconstructModules - resolve dependencies and then call each
85 module constructor in turn.
88 PROCEDURE DeconstructModules (applicationmodule, libname: ADDRESS;
89 argc: INTEGER; argv, envp: ADDRESS) ;
91 M2Dependent.DeconstructModules (applicationmodule, libname,
93 END DeconstructModules ;
97 RegisterModule - adds module name to the list of outstanding
98 modules which need to have their dependencies
99 explored to determine initialization order.
102 PROCEDURE RegisterModule (name, libname: ADDRESS;
103 init, fini: ArgCVEnvP;
104 dependencies: PROC) ;
106 M2Dependent.RegisterModule (name, libname, init, fini, dependencies)
111 RequestDependant - used to specify that modulename is dependant upon
112 module dependantmodule.
115 PROCEDURE RequestDependant (modulename, libname,
116 dependantmodule, dependantlibname: ADDRESS) ;
118 M2Dependent.RequestDependant (modulename, libname,
119 dependantmodule, dependantlibname)
120 END RequestDependant ;
124 ExecuteReverse - execute the procedure associated with procptr
125 and then proceed to try and execute all previous
126 procedures in the chain.
129 PROCEDURE ExecuteReverse (procptr: ProcedureChain) ;
131 WHILE procptr # NIL DO
132 procptr^.p ; (* Invoke the procedure. *)
133 procptr := procptr^.prev
139 ExecuteTerminationProcedures - calls each installed termination procedure
143 PROCEDURE ExecuteTerminationProcedures ;
145 ExecuteReverse (TerminateProc.tail)
146 END ExecuteTerminationProcedures ;
150 ExecuteInitialProcedures - executes the initial procedures installed by
151 InstallInitialProcedure.
154 PROCEDURE ExecuteInitialProcedures ;
156 ExecuteReverse (InitialProc.tail)
157 END ExecuteInitialProcedures ;
161 AppendProc - append proc to the end of the procedure list
165 PROCEDURE AppendProc (VAR proclist: ProcedureList; proc: PROC) : BOOLEAN ;
167 pdes: ProcedureChain ;
172 prev := proclist.tail ;
175 IF proclist.head = NIL
177 proclist.head := pdes
179 proclist.tail := pdes ;
185 InstallTerminationProcedure - installs a procedure, p, which will
186 be called when the procedure
187 ExecuteTerminationProcedures
188 is invoked. It returns TRUE if the
189 procedure is installed.
192 PROCEDURE InstallTerminationProcedure (p: PROC) : BOOLEAN ;
194 RETURN AppendProc (TerminateProc, p)
195 END InstallTerminationProcedure ;
199 InstallInitialProcedure - installs a procedure to be executed just
200 before the BEGIN code section of the
204 PROCEDURE InstallInitialProcedure (p: PROC) : BOOLEAN ;
206 RETURN AppendProc (InitialProc, p)
207 END InstallInitialProcedure ;
211 HALT - terminate the current program. The procedure
212 ExecuteTerminationProcedures
213 is called before the program is stopped. The parameter
214 exitcode is optional. If the parameter is not supplied
215 HALT will call libc 'abort', otherwise it will exit with
216 the code supplied. Supplying a parameter to HALT has the
217 same effect as calling ExitOnHalt with the same code and
218 then calling HALT with no parameter.
221 PROCEDURE HALT ([exitcode: INTEGER = -1]) <* noreturn *> ;
226 ExitValue := exitcode
230 (* double HALT found *)
234 ExecuteTerminationProcedures ;
246 Terminate - provides compatibility for pim. It calls exit with
247 the exitcode provided in a prior call to ExitOnHalt
248 (or zero if ExitOnHalt was never called). It does
249 not call ExecuteTerminationProcedures.
252 PROCEDURE Terminate <* noreturn *> ;
259 ErrorString - writes a string to stderr.
262 PROCEDURE ErrorString (a: ARRAY OF CHAR) ;
266 n := write (stderrFd, ADR (a), StrLen (a))
271 ErrorStringC - writes a string to stderr.
274 PROCEDURE ErrorStringC (str: ADDRESS) ;
278 len := write (stderrFd, str, strlen (str))
283 ErrorMessage - emits an error message to stderr and then calls exit (1).
286 PROCEDURE ErrorMessage (message: ARRAY OF CHAR;
287 filename: ARRAY OF CHAR;
289 function: ARRAY OF CHAR) <* noreturn *> ;
291 buffer: ARRAY [0..10] OF CHAR ;
293 ErrorString (filename) ; ErrorString(':') ;
294 CardToStr (line, 0, buffer) ;
295 ErrorString (buffer) ; ErrorString(':') ;
296 IF NOT StrEqual (function, '')
298 ErrorString ('in ') ;
299 ErrorString (function) ;
300 ErrorString (' has caused ') ;
302 ErrorString (message) ;
303 buffer[0] := nl ; buffer[1] := nul ;
304 ErrorString (buffer) ;
310 ErrorMessageC - emits an error message to stderr and then calls exit (1).
313 PROCEDURE ErrorMessageC (message, filename: ADDRESS;
315 function: ADDRESS) <* noreturn *> ;
317 buffer: ARRAY [0..10] OF CHAR ;
319 ErrorStringC (filename) ; ErrorString (':') ;
320 CardToStr (line, 0, buffer) ;
321 ErrorString (buffer) ; ErrorString(':') ;
322 IF strlen (function) > 0
324 ErrorString ('in ') ;
325 ErrorStringC (function) ;
326 ErrorString (' has caused ') ;
328 ErrorStringC (message) ;
329 buffer[0] := nl ; buffer[1] := nul ;
330 ErrorString (buffer) ;
336 HaltC - provides a more user friendly version of HALT, which takes
337 four parameters to aid debugging. It writes an error message
338 to stderr and calls exit (1).
341 PROCEDURE HaltC (description, filename, function: ADDRESS; line: CARDINAL) ;
343 ErrorMessageC (description, filename, line, function)
348 Halt - provides a more user friendly version of HALT, which takes
349 four parameters to aid debugging. It writes an error message
350 to stderr and calls exit (1).
353 PROCEDURE Halt (description, filename, function: ARRAY OF CHAR; line: CARDINAL) ;
355 ErrorMessage (description, filename, line, function)
360 The following are the runtime exception handler routines.
363 PROCEDURE AssignmentException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
365 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
366 filename, line, column, scope, message)
367 END AssignmentException ;
370 PROCEDURE ReturnException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
372 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
373 filename, line, column, scope, message)
374 END ReturnException ;
377 PROCEDURE IncException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
379 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
380 filename, line, column, scope, message)
384 PROCEDURE DecException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
386 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
387 filename, line, column, scope, message)
391 PROCEDURE InclException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
393 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
394 filename, line, column, scope, message)
398 PROCEDURE ExclException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
400 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
401 filename, line, column, scope, message)
405 PROCEDURE ShiftException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
407 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
408 filename, line, column, scope, message)
412 PROCEDURE RotateException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
414 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
415 filename, line, column, scope, message)
416 END RotateException ;
419 PROCEDURE StaticArraySubscriptException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
421 RTExceptions.Raise (ORD (M2EXCEPTION.indexException),
422 filename, line, column, scope, message)
423 END StaticArraySubscriptException ;
426 PROCEDURE DynamicArraySubscriptException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
428 RTExceptions.Raise (ORD (M2EXCEPTION.indexException),
429 filename, line, column, scope, message)
430 END DynamicArraySubscriptException ;
433 PROCEDURE ForLoopBeginException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
435 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
436 filename, line, column, scope, message)
437 END ForLoopBeginException ;
440 PROCEDURE ForLoopToException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
442 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
443 filename, line, column, scope, message)
444 END ForLoopToException ;
447 PROCEDURE ForLoopEndException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
449 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
450 filename, line, column, scope, message)
451 END ForLoopEndException ;
454 PROCEDURE PointerNilException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
456 RTExceptions.Raise (ORD (M2EXCEPTION.invalidLocation),
457 filename, line, column, scope, message)
458 END PointerNilException ;
461 PROCEDURE NoReturnException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
463 RTExceptions.Raise (ORD (M2EXCEPTION.functionException),
464 filename, line, column, scope, message)
465 END NoReturnException ;
468 PROCEDURE CaseException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
470 RTExceptions.Raise (ORD (M2EXCEPTION.caseSelectException),
471 filename, line, column, scope, message)
475 PROCEDURE WholeNonPosDivException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
477 RTExceptions.Raise (ORD (M2EXCEPTION.wholeDivException),
478 filename, line, column, scope, message)
479 END WholeNonPosDivException ;
482 PROCEDURE WholeNonPosModException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
484 RTExceptions.Raise (ORD (M2EXCEPTION.wholeDivException),
485 filename, line, column, scope, message)
486 END WholeNonPosModException ;
489 PROCEDURE WholeZeroDivException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
491 RTExceptions.Raise(ORD (M2EXCEPTION.wholeDivException),
492 filename, line, column, scope, message)
493 END WholeZeroDivException ;
496 PROCEDURE WholeZeroRemException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
498 RTExceptions.Raise (ORD (M2EXCEPTION.wholeDivException),
499 filename, line, column, scope, message)
500 END WholeZeroRemException ;
503 PROCEDURE WholeValueException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
505 RTExceptions.Raise (ORD (M2EXCEPTION.wholeValueException),
506 filename, line, column, scope, message)
507 END WholeValueException ;
510 PROCEDURE RealValueException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
512 RTExceptions.Raise (ORD (M2EXCEPTION.realValueException),
513 filename, line, column, scope, message)
514 END RealValueException ;
517 PROCEDURE ParameterException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
519 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
520 filename, line, column, scope, message)
521 END ParameterException ;
524 PROCEDURE NoException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
526 RTExceptions.Raise (ORD (M2EXCEPTION.exException),
527 filename, line, column, scope, message)
532 ExitOnHalt - if HALT is executed then call exit with the exit code, e.
535 PROCEDURE ExitOnHalt (e: INTEGER) ;
543 Length - returns the length of a string, a. This is called whenever
544 the user calls LENGTH and the parameter cannot be calculated
548 PROCEDURE Length (a: ARRAY OF CHAR) : CARDINAL ;
554 WHILE (l<=h) AND (a[l]#nul) DO
562 InitProcList - initialize the head and tail pointers to NIL.
565 PROCEDURE InitProcList (VAR p: ProcedureList) ;
573 Init - initialize the initial, terminate procedure lists and booleans.
578 InitProcList (InitialProc) ;
579 InitProcList (TerminateProc) ;
582 CallExit := FALSE (* default by calling abort *)
587 CheckInitialized - checks to see if this module has been initialized
588 and if it has not it calls Init. We need this
589 approach as this module is called by module ctors
590 before we reach main.
593 PROCEDURE CheckInitialized ;
597 Initialized := TRUE ;
600 END CheckInitialized ;