]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/m2/gm2-libs/M2RTS.mod
Update copyright years.
[thirdparty/gcc.git] / gcc / m2 / gm2-libs / M2RTS.mod
CommitLineData
1eee94d3
GM
1(* M2RTS.mod Implements the run time system facilities of Modula-2.
2
83ffe9cd 3Copyright (C) 2001-2023 Free Software Foundation, Inc.
1eee94d3
GM
4Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
5
6This file is part of GNU Modula-2.
7
8GNU Modula-2 is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3, or (at your option)
11any later version.
12
13GNU Modula-2 is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16General Public License for more details.
17
18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25<http://www.gnu.org/licenses/>. *)
26
27IMPLEMENTATION MODULE M2RTS ;
28
29
30FROM libc IMPORT abort, exit, write, getenv, printf ;
31(* FROM Builtins IMPORT strncmp, strcmp ; not available during bootstrap. *)
32FROM NumberIO IMPORT CardToStr ;
33FROM StrLib IMPORT StrCopy, StrLen, StrEqual ;
34FROM SYSTEM IMPORT ADDRESS, ADR ;
35FROM ASCII IMPORT nl, nul ;
36FROM Storage IMPORT ALLOCATE ;
37
38IMPORT RTExceptions ;
39IMPORT M2EXCEPTION ;
40IMPORT M2Dependent ;
41
42TYPE
43 PtrToChar = POINTER TO CHAR ;
44
45 ProcedureList = RECORD
46 head, tail: ProcedureChain
47 END ;
48
49 ProcedureChain = POINTER TO RECORD
50 p : PROC ;
51 prev,
52 next: ProcedureChain ;
53 END ;
54
55
56VAR
57 InitialProc,
58 TerminateProc: ProcedureList ;
59 ExitValue : INTEGER ;
60 isHalting,
61 CallExit : BOOLEAN ;
62 Initialized : BOOLEAN ;
63
64
65(*
66 ConstructModules - resolve dependencies and then call each
67 module constructor in turn.
68*)
69
70PROCEDURE ConstructModules (applicationmodule: ADDRESS;
71 argc: INTEGER; argv, envp: ADDRESS) ;
72BEGIN
73 M2Dependent.ConstructModules (applicationmodule, argc, argv, envp)
74END ConstructModules ;
75
76
77(*
78 DeconstructModules - resolve dependencies and then call each
79 module constructor in turn.
80*)
81
82PROCEDURE DeconstructModules (applicationmodule: ADDRESS;
83 argc: INTEGER; argv, envp: ADDRESS) ;
84BEGIN
85 M2Dependent.DeconstructModules (applicationmodule, argc, argv, envp)
86END DeconstructModules ;
87
88
89(*
90 RegisterModule - adds module name to the list of outstanding
91 modules which need to have their dependencies
92 explored to determine initialization order.
93*)
94
95PROCEDURE RegisterModule (name: ADDRESS;
96 init, fini: ArgCVEnvP;
97 dependencies: PROC) ;
98BEGIN
99 M2Dependent.RegisterModule (name, init, fini, dependencies)
100END RegisterModule ;
101
102
103(*
104 RequestDependant - used to specify that modulename is dependant upon
105 module dependantmodule.
106*)
107
108PROCEDURE RequestDependant (modulename, dependantmodule: ADDRESS) ;
109BEGIN
110 M2Dependent.RequestDependant (modulename, dependantmodule)
111END RequestDependant ;
112
113
114(*
115 ExecuteReverse - execute the procedure associated with procptr
116 and then proceed to try and execute all previous
117 procedures in the chain.
118*)
119
120PROCEDURE ExecuteReverse (procptr: ProcedureChain) ;
121BEGIN
122 WHILE procptr # NIL DO
123 procptr^.p ; (* Invoke the procedure. *)
124 procptr := procptr^.prev
125 END
126END ExecuteReverse ;
127
128
129(*
130 ExecuteTerminationProcedures - calls each installed termination procedure
131 in reverse order.
132*)
133
134PROCEDURE ExecuteTerminationProcedures ;
135BEGIN
136 ExecuteReverse (TerminateProc.tail)
137END ExecuteTerminationProcedures ;
138
139
140(*
141 ExecuteInitialProcedures - executes the initial procedures installed by
142 InstallInitialProcedure.
143*)
144
145PROCEDURE ExecuteInitialProcedures ;
146BEGIN
147 ExecuteReverse (InitialProc.tail)
148END ExecuteInitialProcedures ;
149
150
151(*
152 AppendProc - append proc to the end of the procedure list
153 defined by proclist.
154*)
155
156PROCEDURE AppendProc (VAR proclist: ProcedureList; proc: PROC) : BOOLEAN ;
157VAR
158 pdes: ProcedureChain ;
159BEGIN
160 NEW (pdes) ;
161 WITH pdes^ DO
162 p := proc ;
163 prev := proclist.tail ;
164 next := NIL
165 END ;
166 IF proclist.head = NIL
167 THEN
168 proclist.head := pdes
169 END ;
170 proclist.tail := pdes ;
171 RETURN TRUE
172END AppendProc ;
173
174
175(*
176 InstallTerminationProcedure - installs a procedure, p, which will
177 be called when the procedure
178 ExecuteTerminationProcedures
179 is invoked. It returns TRUE if the
180 procedure is installed.
181*)
182
183PROCEDURE InstallTerminationProcedure (p: PROC) : BOOLEAN ;
184BEGIN
185 RETURN AppendProc (TerminateProc, p)
186END InstallTerminationProcedure ;
187
188
189(*
190 InstallInitialProcedure - installs a procedure to be executed just
191 before the BEGIN code section of the
192 main program module.
193*)
194
195PROCEDURE InstallInitialProcedure (p: PROC) : BOOLEAN ;
196BEGIN
197 RETURN AppendProc (InitialProc, p)
198END InstallInitialProcedure ;
199
200
201(*
202 HALT - terminate the current program. The procedure
203 ExecuteTerminationProcedures
204 is called before the program is stopped. The parameter
205 exitcode is optional. If the parameter is not supplied
206 HALT will call libc 'abort', otherwise it will exit with
207 the code supplied. Supplying a parameter to HALT has the
208 same effect as calling ExitOnHalt with the same code and
209 then calling HALT with no parameter.
210*)
211
212PROCEDURE HALT ([exitcode: INTEGER = -1]) <* noreturn *> ;
213BEGIN
214 IF exitcode#-1
215 THEN
216 CallExit := TRUE ;
217 ExitValue := exitcode
218 END ;
219 IF isHalting
220 THEN
221 (* double HALT found *)
222 exit(-1)
223 ELSE
224 isHalting := TRUE ;
225 ExecuteTerminationProcedures ;
226 END ;
227 IF CallExit
228 THEN
229 exit(ExitValue)
230 ELSE
231 abort
232 END
233END HALT ;
234
235
236(*
237 Terminate - provides compatibility for pim. It calls exit with
238 the exitcode provided in a prior call to ExitOnHalt
239 (or zero if ExitOnHalt was never called). It does
240 not call ExecuteTerminationProcedures.
241*)
242
243PROCEDURE Terminate <* noreturn *> ;
244BEGIN
245 exit (ExitValue)
246END Terminate ;
247
248
249(*
250 ErrorString - writes a string to stderr.
251*)
252
253PROCEDURE ErrorString (a: ARRAY OF CHAR) ;
254VAR
255 n: INTEGER ;
256BEGIN
257 n := write (2, ADR (a), StrLen (a))
258END ErrorString ;
259
260
261(*
262 ErrorMessage - emits an error message to stderr and then calls exit (1).
263*)
264
265PROCEDURE ErrorMessage (message: ARRAY OF CHAR;
266 file: ARRAY OF CHAR;
267 line: CARDINAL;
268 function: ARRAY OF CHAR) <* noreturn *> ;
269VAR
270 LineNo: ARRAY [0..10] OF CHAR ;
271BEGIN
272 ErrorString (file) ; ErrorString(':') ;
273 CardToStr (line, 0, LineNo) ;
274 ErrorString (LineNo) ; ErrorString(':') ;
275 IF NOT StrEqual (function, '')
276 THEN
277 ErrorString ('in ') ;
278 ErrorString (function) ;
279 ErrorString (' has caused ') ;
280 END ;
281 ErrorString (message) ;
282 LineNo[0] := nl ; LineNo[1] := nul ;
283 ErrorString (LineNo) ;
284 exit (1)
285END ErrorMessage ;
286
287
288(*
289 Halt - provides a more user friendly version of HALT, which takes
290 four parameters to aid debugging.
291*)
292
293PROCEDURE Halt (file: ARRAY OF CHAR; line: CARDINAL;
294 function: ARRAY OF CHAR; description: ARRAY OF CHAR) ;
295BEGIN
296 ErrorMessage (description, file, line, function) ;
297 HALT
298END Halt ;
299
300
301(*
302 The following are the runtime exception handler routines.
303*)
304
305PROCEDURE AssignmentException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
306BEGIN
307 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
308 filename, line, column, scope, message)
309END AssignmentException ;
310
311
312PROCEDURE ReturnException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
313BEGIN
314 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
315 filename, line, column, scope, message)
316END ReturnException ;
317
318
319PROCEDURE IncException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
320BEGIN
321 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
322 filename, line, column, scope, message)
323END IncException ;
324
325
326PROCEDURE DecException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
327BEGIN
328 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
329 filename, line, column, scope, message)
330END DecException ;
331
332
333PROCEDURE InclException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
334BEGIN
335 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
336 filename, line, column, scope, message)
337END InclException ;
338
339
340PROCEDURE ExclException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
341BEGIN
342 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
343 filename, line, column, scope, message)
344END ExclException ;
345
346
347PROCEDURE ShiftException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
348BEGIN
349 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
350 filename, line, column, scope, message)
351END ShiftException ;
352
353
354PROCEDURE RotateException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
355BEGIN
356 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
357 filename, line, column, scope, message)
358END RotateException ;
359
360
361PROCEDURE StaticArraySubscriptException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
362BEGIN
363 RTExceptions.Raise (ORD (M2EXCEPTION.indexException),
364 filename, line, column, scope, message)
365END StaticArraySubscriptException ;
366
367
368PROCEDURE DynamicArraySubscriptException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
369BEGIN
370 RTExceptions.Raise (ORD (M2EXCEPTION.indexException),
371 filename, line, column, scope, message)
372END DynamicArraySubscriptException ;
373
374
375PROCEDURE ForLoopBeginException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
376BEGIN
377 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
378 filename, line, column, scope, message)
379END ForLoopBeginException ;
380
381
382PROCEDURE ForLoopToException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
383BEGIN
384 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
385 filename, line, column, scope, message)
386END ForLoopToException ;
387
388
389PROCEDURE ForLoopEndException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
390BEGIN
391 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
392 filename, line, column, scope, message)
393END ForLoopEndException ;
394
395
396PROCEDURE PointerNilException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
397BEGIN
398 RTExceptions.Raise (ORD (M2EXCEPTION.invalidLocation),
399 filename, line, column, scope, message)
400END PointerNilException ;
401
402
403PROCEDURE NoReturnException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
404BEGIN
405 RTExceptions.Raise (ORD (M2EXCEPTION.functionException),
406 filename, line, column, scope, message)
407END NoReturnException ;
408
409
410PROCEDURE CaseException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
411BEGIN
412 RTExceptions.Raise (ORD (M2EXCEPTION.caseSelectException),
413 filename, line, column, scope, message)
414END CaseException ;
415
416
417PROCEDURE WholeNonPosDivException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
418BEGIN
419 RTExceptions.Raise (ORD (M2EXCEPTION.wholeDivException),
420 filename, line, column, scope, message)
421END WholeNonPosDivException ;
422
423
424PROCEDURE WholeNonPosModException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
425BEGIN
426 RTExceptions.Raise (ORD (M2EXCEPTION.wholeDivException),
427 filename, line, column, scope, message)
428END WholeNonPosModException ;
429
430
431PROCEDURE WholeZeroDivException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
432BEGIN
433 RTExceptions.Raise(ORD (M2EXCEPTION.wholeDivException),
434 filename, line, column, scope, message)
435END WholeZeroDivException ;
436
437
438PROCEDURE WholeZeroRemException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
439BEGIN
440 RTExceptions.Raise (ORD (M2EXCEPTION.wholeDivException),
441 filename, line, column, scope, message)
442END WholeZeroRemException ;
443
444
445PROCEDURE WholeValueException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
446BEGIN
447 RTExceptions.Raise (ORD (M2EXCEPTION.wholeValueException),
448 filename, line, column, scope, message)
449END WholeValueException ;
450
451
452PROCEDURE RealValueException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
453BEGIN
454 RTExceptions.Raise (ORD (M2EXCEPTION.realValueException),
455 filename, line, column, scope, message)
456END RealValueException ;
457
458
459PROCEDURE ParameterException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
460BEGIN
461 RTExceptions.Raise (ORD (M2EXCEPTION.rangeException),
462 filename, line, column, scope, message)
463END ParameterException ;
464
465
466PROCEDURE NoException (filename: ADDRESS; line, column: CARDINAL; scope, message: ADDRESS) ;
467BEGIN
468 RTExceptions.Raise (ORD (M2EXCEPTION.exException),
469 filename, line, column, scope, message)
470END NoException ;
471
472
473(*
474 ExitOnHalt - if HALT is executed then call exit with the exit code, e.
475*)
476
477PROCEDURE ExitOnHalt (e: INTEGER) ;
478BEGIN
479 ExitValue := e ;
480 CallExit := TRUE
481END ExitOnHalt ;
482
483
484(*
485 Length - returns the length of a string, a. This is called whenever
486 the user calls LENGTH and the parameter cannot be calculated
487 at compile time.
488*)
489
490PROCEDURE Length (a: ARRAY OF CHAR) : CARDINAL ;
491VAR
492 l, h: CARDINAL ;
493BEGIN
494 l := 0 ;
495 h := HIGH(a) ;
496 WHILE (l<=h) AND (a[l]#nul) DO
497 INC(l)
498 END ;
499 RETURN( l )
500END Length ;
501
502
503(*
504 InitProcList - initialize the head and tail pointers to NIL.
505*)
506
507PROCEDURE InitProcList (VAR p: ProcedureList) ;
508BEGIN
509 p.head := NIL ;
510 p.tail := NIL
511END InitProcList ;
512
513
514(*
515 Init - initialize the initial, terminate procedure lists and booleans.
516*)
517
518PROCEDURE Init ;
519BEGIN
520 InitProcList (InitialProc) ;
521 InitProcList (TerminateProc) ;
522 ExitValue := 0 ;
523 isHalting := FALSE ;
524 CallExit := FALSE (* default by calling abort *)
525END Init ;
526
527
528(*
529 CheckInitialized - checks to see if this module has been initialized
530 and if it has not it calls Init. We need this
531 approach as this module is called by module ctors
532 before we reach main.
533*)
534
535PROCEDURE CheckInitialized ;
536BEGIN
537 IF NOT Initialized
538 THEN
539 Initialized := TRUE ;
540 Init
541 END
542END CheckInitialized ;
543
544
545BEGIN
546 CheckInitialized
547END M2RTS.