blob: 47ada7b5a98b172c2026b476cf92fd078627c3b6 [file] [log] [blame]
(* M2Scaffold.mod declare and create scaffold entities.
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
This file is part of GNU Modula-2.
GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. *)
IMPLEMENTATION MODULE M2Scaffold ;
FROM SymbolTable IMPORT NulSym, MakeProcedure, PutFunction,
PutPublic, PutCtor, PutParam, IsProcedure,
MakeConstant, PutExtern, MakeArray, PutArray,
MakeSubrange, PutSubrange,
MakeSubscript, PutSubscript, PutArraySubscript,
MakeVar, PutVar, MakeProcedureCtorExtern,
GetMainModule, GetModuleCtors, MakeDefImp,
PutModuleCtorExtern,
GetSymName, StartScope, EndScope ;
FROM NameKey IMPORT NulName, Name, MakeKey, makekey, KeyToCharStar ;
FROM M2Base IMPORT Integer, Cardinal ;
FROM M2System IMPORT Address ;
FROM M2LexBuf IMPORT GetTokenNo ;
FROM Assertion IMPORT Assert ;
FROM Lists IMPORT List, InitList, IncludeItemIntoList, NoOfItemsInList, GetItemFromList ;
FROM M2MetaError IMPORT MetaErrorT0 ;
FROM SFIO IMPORT OpenToWrite, WriteS, ReadS, OpenToRead, Exists ;
FROM FIO IMPORT File, EOF, IsNoError, Close ;
FROM M2Options IMPORT GetUselist, ScaffoldStatic ;
FROM M2Base IMPORT Proc ;
FROM M2Quads IMPORT PushTFtok, PushTtok, PushT, BuildDesignatorArray, BuildAssignment,
BuildProcedureCall ;
FROM M2Batch IMPORT IsModuleKnown, Get ;
FROM DynamicStrings IMPORT String, InitString, KillString, ConCat, RemoveWhitePrefix,
EqualArray, Mark, Assign, Fin, InitStringChar, Length, Slice, Equal,
RemoveComment, string ;
CONST
Comment = '#' ; (* Comment leader *)
VAR
uselistModules,
ctorModules,
ctorGlobals : List ;
ctorArray,
ctorArrayType : CARDINAL ;
(* The dynamic scaffold takes the form:
static void _M2_init (int argc, char *argv[], char *envp[])
{
M2RTS_ConstructModules (module_name, argc, argv, envp);
}
static void _M2_finish (int argc, char *argv[], char *envp[])
{
M2RTS_Terminate ();
M2RTS_DeconstructModules (module_name, argc, argv, envp);
}
int
main (int argc, char *argv[], char *envp[])
{
init (argc, argv, envp);
finish ();
return (0);
} *)
(*
DeclareCtorArrayType - declare an ARRAY [0..high] OF PROC which will
be used to reference every module ctor.
*)
PROCEDURE DeclareCtorArrayType (tokenno: CARDINAL; high: CARDINAL) : CARDINAL ;
VAR
subscript,
subrange : CARDINAL ;
BEGIN
(* ctorArrayType = ARRAY [0..n] OF PROC ; *)
ctorArrayType := MakeArray (tokenno, MakeKey ('ctorGlobalType')) ;
PutArray (ctorArrayType, Proc) ;
subrange := MakeSubrange (tokenno, NulName) ;
PutSubrange (subrange,
MakeConstant (tokenno, 0),
MakeConstant (tokenno, high),
Cardinal) ;
subscript := MakeSubscript () ;
PutSubscript (subscript, subrange) ;
PutArraySubscript (ctorArrayType, subscript) ;
RETURN ctorArrayType
END DeclareCtorArrayType ;
(*
DeclareCtorGlobal - declare the ctorArray variable.
*)
PROCEDURE DeclareCtorGlobal (tokenno: CARDINAL) ;
VAR
n: CARDINAL ;
BEGIN
n := NoOfItemsInList (ctorGlobals) ;
ctorArrayType := DeclareCtorArrayType (tokenno, n) ;
ctorArray := MakeVar (tokenno, MakeKey ('_M2_ctorArray')) ;
PutVar (ctorArray, ctorArrayType)
END DeclareCtorGlobal ;
(*
ForeachModuleCallInit - is only called when -fscaffold-static is enabled.
precondition: the module list will be ordered.
postcondition: foreach module in the application universe
call _M2_module_init (argc, argv, envp);
*)
PROCEDURE ForeachModuleCallInit (tok: CARDINAL; argc, argv, envp: CARDINAL) ;
VAR
module : CARDINAL ;
i, n : CARDINAL ;
ctor, init,
fini, dep : CARDINAL ;
BEGIN
i := 1 ;
n := NoOfItemsInList (uselistModules) ;
WHILE i <= n DO
module := GetItemFromList (uselistModules, i) ;
IF module # NulSym
THEN
GetModuleCtors (module, ctor, init, fini, dep) ;
IF init # NulSym
THEN
PushTtok (init, tok) ;
PushTtok (argc, tok) ;
PushTtok (argv, tok) ;
PushTtok (envp, tok) ;
PushT (3) ;
BuildProcedureCall (tok)
END
END ;
INC (i)
END
END ForeachModuleCallInit ;
(*
ForeachModuleCallFinish - precondition: the module list will be ordered.
postcondition: foreach module in the application universe
call _M2_module_finish (argc, argv, envp);
*)
PROCEDURE ForeachModuleCallFinish (tok: CARDINAL; argc, argv, envp: CARDINAL) ;
VAR
module : CARDINAL ;
i : CARDINAL ;
ctor, init,
fini, dep : CARDINAL ;
BEGIN
i := NoOfItemsInList (uselistModules) ;
WHILE i >= 1 DO
module := GetItemFromList (uselistModules, i) ;
IF module # NulSym
THEN
GetModuleCtors (module, ctor, init, fini, dep) ;
IF fini # NulSym
THEN
PushTtok (fini, tok) ;
PushTtok (argc, tok) ;
PushTtok (argv, tok) ;
PushTtok (envp, tok) ;
PushT (3) ;
BuildProcedureCall (tok)
END
END ;
DEC (i)
END
END ForeachModuleCallFinish ;
(*
PopulateCtorArray - assign each element of the ctorArray to the external module ctor.
This is only used to force the linker to pull in the ctors from
a library.
*)
PROCEDURE PopulateCtorArray (tok: CARDINAL) ;
VAR
i, n: CARDINAL ;
BEGIN
n := NoOfItemsInList (ctorModules) ;
i := 1 ;
WHILE i <= n DO
PushTFtok (ctorArray, ctorArrayType, tok) ;
PushTtok (MakeConstant (tok, i), tok) ;
BuildDesignatorArray ;
PushTtok (GetItemFromList (ctorModules, i), tok) ;
BuildAssignment (tok) ;
INC (i)
END
END PopulateCtorArray ;
(*
LookupModuleSym - returns a defimp module. It looks up an existing
module and if this does not exist creates a new one.
*)
PROCEDURE LookupModuleSym (tok: CARDINAL; name: Name) : CARDINAL ;
VAR
sym: CARDINAL ;
BEGIN
sym := Get (name) ;
IF sym = NulSym
THEN
sym := MakeDefImp (tok, name)
END ;
IF sym # GetMainModule ()
THEN
PutModuleCtorExtern (tok, sym)
END ;
RETURN sym
END LookupModuleSym ;
(*
ReadModules - populate ctorGlobals with the modules specified by -fuselist=filename.
*)
PROCEDURE ReadModules (tok: CARDINAL; filename: String) ;
VAR
f : File ;
s : String ;
name: Name ;
BEGIN
InitList (ctorGlobals) ;
InitList (uselistModules) ;
f := OpenToRead (filename) ;
WHILE NOT EOF (f) DO
s := ReadS (f) ;
s := RemoveComment (RemoveWhitePrefix (s), Comment) ;
IF (NOT Equal (Mark (InitStringChar (Comment)),
Mark (Slice (s, 0, Length (Mark (InitStringChar (Comment)))-1)))) AND
(NOT EqualArray (s, ''))
THEN
name := makekey (string (s)) ;
IncludeItemIntoList (ctorGlobals, name) ;
IncludeItemIntoList (uselistModules, LookupModuleSym (tok, name))
END ;
s := KillString (s)
END ;
Close (f)
END ReadModules ;
(*
CreateCtorList - uses GetUselist as the filename and then reads the list of modules.
*)
PROCEDURE CreateCtorList (tok: CARDINAL) : BOOLEAN ;
VAR
filename: String ;
BEGIN
filename := GetUselist () ;
IF filename = NIL
THEN
RETURN FALSE
ELSE
IF Exists (filename)
THEN
ReadModules (tok, filename)
ELSE
MetaErrorT0 (tok,
'{%E}the filename specified by the -fuselist= option does not exist') ;
RETURN FALSE
END
END ;
RETURN TRUE
END CreateCtorList ;
(*
DeclareModuleExtern - declare the extern _M2_modulename_ctor, _M2_modulename_init,
_M2_modulename_fini, _M2_modulename_dep for each external module.
*)
PROCEDURE DeclareModuleExtern (tokenno: CARDINAL) ;
VAR
init,
fini,
dep,
ctor,
module: CARDINAL ;
n, i : CARDINAL ;
BEGIN
InitList (ctorModules) ;
i := 1 ;
n := NoOfItemsInList (uselistModules) ;
WHILE i <= n DO
module := GetItemFromList (uselistModules, i) ;
IF module # GetMainModule ()
THEN
PutModuleCtorExtern (tokenno, module)
END ;
GetModuleCtors (module, ctor, init, fini, dep) ;
IncludeItemIntoList (ctorModules, ctor) ;
INC (i)
END
END DeclareModuleExtern ;
(*
DeclareScaffoldFunctions - declare main, _M2_init,_M2_finish
and _M2_link to the modula-2
front end.
*)
PROCEDURE DeclareScaffoldFunctions (tokenno: CARDINAL) ;
BEGIN
IF CreateCtorList (tokenno)
THEN
DeclareCtorGlobal (tokenno) ;
DeclareModuleExtern (tokenno) ;
linkFunction := MakeProcedure (tokenno, MakeKey ("_M2_link"))
END ;
mainFunction := MakeProcedure (tokenno, MakeKey ("main")) ;
StartScope (mainFunction) ;
PutFunction (mainFunction, Integer) ;
DeclareArgEnvParams (tokenno, mainFunction) ;
PutPublic (mainFunction, TRUE) ;
EndScope ;
initFunction := MakeProcedure (tokenno, MakeKey ("_M2_init")) ;
DeclareArgEnvParams (tokenno, initFunction) ;
finiFunction := MakeProcedure (tokenno, MakeKey ("_M2_finish")) ;
DeclareArgEnvParams (tokenno, finiFunction)
END DeclareScaffoldFunctions ;
(*
DeclareArgEnvParams - declares (int argc, void *argv, void *envp)
*)
PROCEDURE DeclareArgEnvParams (tokno: CARDINAL; proc: CARDINAL) ;
BEGIN
Assert (IsProcedure (proc)) ;
StartScope (proc) ;
Assert (PutParam (tokno, proc, 1, MakeKey ("argc"), Integer, FALSE)) ;
Assert (PutParam (tokno, proc, 2, MakeKey ("argv"), Address, FALSE)) ;
Assert (PutParam (tokno, proc, 3, MakeKey ("envp"), Address, FALSE)) ;
EndScope
END DeclareArgEnvParams ;
(*
DeclareScaffold - declare scaffold related entities.
*)
PROCEDURE DeclareScaffold (tokno: CARDINAL) ;
BEGIN
DeclareScaffoldFunctions (tokno)
END DeclareScaffold ;
BEGIN
finiFunction := NulSym ;
initFunction := NulSym ;
mainFunction := NulSym ;
linkFunction := NulSym ;
ctorGlobals := NIL ;
ctorModules := NIL ;
uselistModules := NIL
END M2Scaffold.