| (* gm2lgen.mod generates the main C function from a list of module names. |
| |
| Copyright (C) 2001-2023 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/>. *) |
| |
| MODULE gm2lgen ; |
| |
| (* |
| Author : Gaius Mulley |
| Title : gm2lgen |
| Date : Fri Sep 15 14:42:17 BST 1989 |
| Description: Generates the main C function, from a list of module names. |
| *) |
| |
| FROM libc IMPORT exit ; |
| FROM ASCII IMPORT eof ; |
| FROM SArgs IMPORT GetArg ; |
| |
| FROM Indexing IMPORT Index, InitIndex, KillIndex, HighIndice, LowIndice, |
| IncludeIndiceIntoIndex, GetIndice ; |
| |
| FROM FIO IMPORT File, StdIn, StdOut, StdErr, WriteChar, |
| ReadString, WriteString, EOF, IsNoError, WriteLine, Close ; |
| |
| FROM DynamicStrings IMPORT String, InitString, KillString, ConCat, RemoveWhitePrefix, |
| EqualArray, Mark, Assign, Fin, InitStringChar, Length, Slice, Equal, |
| RemoveComment ; |
| |
| FROM M2Printf IMPORT fprintf0, fprintf1, fprintf2 ; |
| FROM SFIO IMPORT OpenToWrite, WriteS, ReadS, OpenToRead ; |
| FROM FormatStrings IMPORT Sprintf0, Sprintf1 ; |
| |
| |
| CONST |
| Comment = '#' ; (* Comment leader *) |
| |
| VAR |
| CPlusPlus, |
| SharedLibrary, |
| NeedInitial, |
| NeedTerminate, |
| ExitNeeded : BOOLEAN ; |
| MainName : String ; |
| FunctionList : Index ; |
| fi, fo : File ; |
| |
| |
| (* |
| OpenOutputFile - attempts to open an output file. |
| *) |
| |
| PROCEDURE OpenOutputFile (s: String) ; |
| BEGIN |
| fo := OpenToWrite(s) ; |
| IF NOT IsNoError(fo) |
| THEN |
| fprintf1(StdErr, 'cannot write to: %s\n', s) ; |
| exit(1) |
| END |
| END OpenOutputFile ; |
| |
| |
| (* |
| OpenInputFile - attempts to open an input file. |
| *) |
| |
| PROCEDURE OpenInputFile (s: String) ; |
| BEGIN |
| fi := OpenToRead(s) ; |
| IF NOT IsNoError(fo) |
| THEN |
| fprintf1 (StdErr, 'cannot open: %s\n', s) ; |
| exit (1) |
| END |
| END OpenInputFile ; |
| |
| |
| (* |
| DisplayHelp - display brief help and exit. |
| *) |
| |
| PROCEDURE DisplayHelp ; |
| BEGIN |
| fprintf0 (StdErr, 'gm2lgen [--exit] [-fcpp] [-fshared] [-h] [--help] [--main function]\n'); |
| fprintf0 (StdErr, ' [-o outputfile] [--terminate] [inputfile]\n'); |
| exit (0) |
| END DisplayHelp ; |
| |
| |
| (* |
| ScanArgs - |
| *) |
| |
| PROCEDURE ScanArgs ; |
| VAR |
| i: CARDINAL ; |
| s: String ; |
| BEGIN |
| i := 1 ; |
| CPlusPlus := FALSE ; |
| NeedTerminate := TRUE ; |
| NeedInitial := TRUE ; |
| ExitNeeded := TRUE ; |
| SharedLibrary := FALSE ; |
| MainName := InitString('main') ; |
| fi := StdIn ; |
| fo := StdOut ; |
| WHILE GetArg(s, i) DO |
| IF EqualArray(s, '--exit') |
| THEN |
| ExitNeeded := FALSE |
| ELSIF EqualArray(s, '--terminate') |
| THEN |
| NeedTerminate := FALSE |
| ELSIF EqualArray(s, '--initial') |
| THEN |
| NeedInitial := FALSE |
| ELSIF EqualArray(s, '-h') OR EqualArray(s, '--help') |
| THEN |
| DisplayHelp |
| ELSIF EqualArray(s, '-fshared') |
| THEN |
| SharedLibrary := TRUE |
| ELSIF EqualArray(s, '-fcpp') |
| THEN |
| CPlusPlus := TRUE |
| ELSIF EqualArray(s, '-o') |
| THEN |
| INC(i) ; |
| IF GetArg(s, i) |
| THEN |
| OpenOutputFile(s) |
| ELSE |
| fprintf0(StdErr, 'missing filename option after -o\n') ; |
| exit(1) |
| END |
| ELSIF EqualArray(s, '--main') |
| THEN |
| INC(i) ; |
| IF GetArg(s, i) |
| THEN |
| MainName := Assign(MainName, s) |
| ELSE |
| fprintf0(StdErr, 'missing functionname after option -main\n') ; |
| exit(1) |
| END |
| ELSE |
| OpenInputFile(s) |
| END ; |
| INC(i) |
| END |
| END ScanArgs ; |
| |
| |
| (* |
| GenInit - |
| *) |
| |
| PROCEDURE GenInit ; |
| BEGIN |
| IF SharedLibrary |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nvoid __attribute__ ((constructor)) init (void);\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nvoid __attribute__ ((constructor)) init (void)\n')))))) |
| ELSE |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nstatic void init (int argc, char *argv[])\n')))))) ; |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('{\n')))))); |
| GenInitializationCalls ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('}\n')))))); |
| END GenInit ; |
| |
| |
| (* |
| GenFinish - |
| *) |
| |
| PROCEDURE GenFinish ; |
| BEGIN |
| IF SharedLibrary |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nvoid __attribute__ ((destructor)) finish (void);\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nvoid __attribute__ ((destructor)) finish (void)\n')))))) |
| ELSE |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nstatic void finish (void)\n')))))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('{\n')))))) ; |
| GenFinalizationCalls ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('}\n')))))) |
| END GenFinish ; |
| |
| |
| (* |
| GenMain - writes out the main() function together with module initialization |
| calls. |
| *) |
| |
| PROCEDURE GenMain ; |
| BEGIN |
| FunctionList := InitIndex(1) ; |
| ScanArgs ; |
| BuildFunctionList ; |
| GenExternals ; |
| GenInit ; |
| GenFinish ; |
| IF NOT SharedLibrary |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf1(Mark(InitString('\nint %s (int argc, char *argv[])\n')), MainName)))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('{\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' init (argc, argv);\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' finish ();\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' return (0);\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('}\n')))))) |
| END ; |
| Close(fo) |
| END GenMain ; |
| |
| |
| (* |
| GenExternals - writes out the external prototypes for each module initializer. |
| *) |
| |
| PROCEDURE GenExternals ; |
| VAR |
| funcname: String ; |
| i, n : CARDINAL ; |
| BEGIN |
| IF ExitNeeded |
| THEN |
| Fin(WriteS(fo, Mark(InitString('extern ')))) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString('"C"')))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' void exit(int);\n\n')))))) ; |
| END ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString('extern "C"')))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' void RTExceptions_DefaultErrorCatch(void);\n')))))) |
| END ; |
| n := HighIndice(FunctionList) ; |
| i := 1 ; |
| WHILE i<=n DO |
| funcname := GetIndice(FunctionList, i) ; |
| Fin(WriteS(fo, Mark(InitString('extern ')))) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString('"C"')))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf1(Mark(InitString(' void _M2_%s_init (int argc, char *argv[]);\n')), funcname)))) ; |
| Fin(WriteS(fo, Mark(InitString('extern ')))) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString('"C"')))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf1(Mark(InitString(' void _M2_%s_finish (void);\n')), funcname)))) ; |
| INC(i) |
| END ; |
| IF NeedTerminate |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nextern ')))))) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString('"C"')))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' void M2RTS_ExecuteTerminationProcedures(void);\n')))))) |
| END ; |
| IF NeedInitial |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString('\nextern ')))))) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString('"C"')))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' void M2RTS_ExecuteInitialProcedures(void);\n')))))) |
| END |
| END GenExternals ; |
| |
| |
| (* |
| GenInitializationCalls - writes out the initialization calls for the modules |
| in the application suit. |
| *) |
| |
| PROCEDURE GenInitializationCalls ; |
| VAR |
| funcname: String ; |
| i, n : CARDINAL ; |
| BEGIN |
| n := HighIndice(FunctionList) ; |
| i := LowIndice(FunctionList) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' try {\n')))))) |
| END ; |
| WHILE i<=n DO |
| IF i=n |
| THEN |
| IF NeedInitial |
| THEN |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' ')))))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' M2RTS_ExecuteInitialProcedures ();\n')))))) |
| END |
| END ; |
| funcname := GetIndice(FunctionList, i) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(InitString(' ')))) |
| END ; |
| IF SharedLibrary |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf1(Mark(InitString(' _M2_%s_init (0, (char **)0);\n')), |
| funcname)))) |
| ELSE |
| Fin(WriteS(fo, Mark(Sprintf1(Mark(InitString(' _M2_%s_init (argc, argv);\n')), |
| funcname)))) |
| END ; |
| INC(i) |
| END ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' }\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' catch (...) {\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' RTExceptions_DefaultErrorCatch();\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' }\n')))))) |
| END ; |
| END GenInitializationCalls ; |
| |
| |
| (* |
| GenFinalizationCalls - writes out the finalization calls for the modules |
| in the application suit. |
| *) |
| |
| PROCEDURE GenFinalizationCalls ; |
| VAR |
| funcname: String ; |
| i, n : CARDINAL ; |
| BEGIN |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' try {\n')))))) |
| END ; |
| IF NeedTerminate |
| THEN |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' ')))))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' M2RTS_ExecuteTerminationProcedures ();\n')))))) |
| END ; |
| n := HighIndice(FunctionList) ; |
| i := LowIndice(FunctionList) ; |
| WHILE i<=n DO |
| funcname := GetIndice(FunctionList, n) ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' ')))))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf1(Mark(InitString(' _M2_%s_finish ();\n')), |
| funcname)))) ; |
| DEC(n) |
| END ; |
| IF ExitNeeded |
| THEN |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' ')))))) |
| END ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' exit (0);\n')))))) |
| END ; |
| IF CPlusPlus |
| THEN |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' }\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' catch (...) {\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' RTExceptions_DefaultErrorCatch();\n')))))) ; |
| Fin(WriteS(fo, Mark(Sprintf0(Mark(InitString(' }\n')))))) |
| END |
| END GenFinalizationCalls ; |
| |
| |
| (* |
| BuildFunctionList - reads in the list of functions and stores them. |
| *) |
| |
| PROCEDURE BuildFunctionList ; |
| VAR |
| s: String ; |
| BEGIN |
| REPEAT |
| s := RemoveComment(RemoveWhitePrefix(ReadS(fi)), Comment) ; |
| IF (NOT Equal(Mark(InitStringChar(Comment)), |
| Mark(Slice(s, 0, Length(Mark(InitStringChar(Comment)))-1)))) AND |
| (NOT EqualArray(s, '')) |
| THEN |
| IncludeIndiceIntoIndex(FunctionList, s) |
| END |
| UNTIL EOF(fi) |
| END BuildFunctionList ; |
| |
| |
| BEGIN |
| GenMain |
| END gm2lgen. |