1 (* M2Swig.mod generates a swig interface file for the main module.
3 Copyright (C) 2008-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 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
22 IMPLEMENTATION MODULE M2Swig ;
24 FROM Storage IMPORT ALLOCATE ;
25 FROM M2Options IMPORT GenerateSwig ;
26 FROM SFIO IMPORT OpenToWrite ;
27 FROM FIO IMPORT File, Close ;
28 FROM NameKey IMPORT Name, KeyToCharStar ;
29 FROM M2Error IMPORT InternalError ;
30 FROM M2Printf IMPORT fprintf0, fprintf1, fprintf2, fprintf3, fprintf4 ;
31 FROM M2AsmUtil IMPORT GetFullScopeAsmName ;
32 FROM SYSTEM IMPORT WORD ;
34 FROM DynamicStrings IMPORT String, InitString, InitStringCharStar, ConCat, Mark,
37 FROM Lists IMPORT List, InitList, KillList, IsItemInList,
38 IncludeItemIntoList, RemoveItemFromList,
39 ForeachItemInListDo, NoOfItemsInList,
42 FROM M2Quads IMPORT IsProcedureScope ;
43 FROM M2System IMPORT IsSystemType, Address, Byte, Loc, Word ;
44 FROM M2Bitset IMPORT Bitset ;
45 FROM Indexing IMPORT Index, InitIndex, KillIndex, HighIndice, PutIndice, GetIndice ;
46 FROM M2Scope IMPORT ScopeBlock, InitScopeBlock, KillScopeBlock ;
48 FROM M2Base IMPORT IsBaseType, Char, Cardinal, Integer, Real, LongReal, ShortReal,
49 LongCard, ShortCard, LongInt, ShortInt, Boolean ;
51 FROM SymbolTable IMPORT GetSymName, IsType, IsProcedure, IsConst, IsVar,
52 GetType, GetNthParam, IsUnbounded, GetMode, ModeOfAddr,
53 NoOfParam, IsConstString, IsConstLit, IsPointer,
54 IsExported, ForeachExportedDo, IsUnboundedParam,
55 IsParameter, IsParameterUnbounded, IsParameterVar,
56 GetParameterShadowVar, GetReadQuads, GetWriteQuads,
59 FROM M2BasicBlock IMPORT BasicBlock, InitBasicBlocks, KillBasicBlocks,
64 UnboundedSig = POINTER TO RECORD
70 includedArray: BOOLEAN ;
72 mainModule : CARDINAL ;
80 DoExported - includes, sym, into the, ToDo, list.
83 PROCEDURE DoExported (sym: CARDINAL) ;
85 IncludeItemIntoList(ToDo, sym)
90 MoveToDone - moves a sym to the, Done, list,
91 providing that it is not already on it.
92 It returns TRUE if the lists were modified.
95 PROCEDURE MoveToDone (sym: CARDINAL) : BOOLEAN ;
97 IF IsItemInList(Done, sym)
100 ELSIF IsItemInList(ToDo, sym)
102 RemoveItemFromList(ToDo, sym) ;
103 IncludeItemIntoList(Done, sym) ;
106 IncludeItemIntoList(Done, sym) ;
112 MoveToToDo - moves a sym to the, ToDo, list,
113 providing that it is not already on it.
114 It returns TRUE if the lists were modified.
117 PROCEDURE MoveToToDo (sym: CARDINAL) : BOOLEAN ;
119 IF IsItemInList(Done, sym)
121 InternalError ('not expecting to get here')
122 ELSIF IsItemInList(ToDo, sym)
126 IncludeItemIntoList(ToDo, sym) ;
133 Trybase - returns TRUE
136 PROCEDURE TryBase (sym: CARDINAL) : BOOLEAN ;
138 IF (sym=Cardinal) OR (sym=Integer) OR (sym=LongInt) OR
139 (sym=LongCard) OR (sym=Char) OR (sym=ShortCard) OR
140 (sym=ShortInt) OR (sym=Real) OR (sym=LongReal) OR
141 (sym=ShortReal) OR (sym=Boolean)
143 RETURN( MoveToDone(sym) )
151 TrySystem - returns TRUE if sym can be moved to the done list.
154 PROCEDURE TrySystem (sym: CARDINAL) : BOOLEAN ;
156 IF (sym=Bitset) OR (sym=Address) OR (sym=Byte) OR (sym=Loc) OR
159 RETURN( MoveToDone(sym) )
167 TryMove - tries to move sym to the done queue as long
171 PROCEDURE TryMove (sym, type: CARDINAL) : BOOLEAN ;
173 IF IsItemInList(Done, type)
193 PROCEDURE TryType (sym: CARDINAL) : BOOLEAN ;
198 type := GetType(sym) ;
199 result := TryDependents(type) ;
200 IF TryMove(sym, type)
213 PROCEDURE TryVar (sym: CARDINAL) : BOOLEAN ;
218 type := GetType(sym) ;
219 result := TryDependents(type) ;
220 IF TryMove(sym, type)
233 PROCEDURE TryProcedure (sym: CARDINAL) : BOOLEAN ;
241 type := GetType(sym) ;
246 IF TryDependents(type)
250 IF NOT IsItemInList(Done, type)
255 p := NoOfParam(sym) ;
258 son := GetNthParam(sym, i) ;
259 IF TryDependents(son)
263 IF NOT IsItemInList(Done, son)
289 PROCEDURE TryUnbounded (sym: CARDINAL) : BOOLEAN ;
294 type := GetType(sym) ;
295 result := TryDependents(type) ;
296 IF TryMove(sym, type)
309 PROCEDURE TryParameter (sym: CARDINAL) : BOOLEAN ;
314 type := GetType(sym) ;
315 result := TryDependents(type) ;
316 IF TryMove(sym, type)
326 TryDependents - returns TRUE if any alteration occurred to any
330 PROCEDURE TryDependents (sym: CARDINAL) : BOOLEAN ;
334 RETURN( TryBase(sym) )
335 ELSIF IsSystemType(sym)
337 RETURN( TrySystem(sym) )
340 RETURN( TryType(sym) )
341 ELSIF IsParameter(sym)
343 RETURN( TryParameter(sym) )
344 ELSIF IsProcedure(sym)
346 RETURN( TryProcedure(sym) )
347 ELSIF IsConstString(sym)
349 RETURN( MoveToDone(sym) )
350 ELSIF IsConstLit(sym)
352 RETURN( MoveToDone(sym) )
353 ELSIF IsVar(sym) AND (GetMode(sym)=ImmediateValue)
355 RETURN( MoveToDone(sym) )
358 RETURN( TryVar(sym) )
359 ELSIF IsUnbounded(sym)
361 RETURN( TryUnbounded(sym) )
369 DoResolveOrder - resolves the declaration order for swig (C).
372 PROCEDURE DoResolveOrder ;
379 n := NoOfItemsInList(ToDo) ;
382 WHILE (i<=n) AND (NOT movement) DO
383 sym := GetItemFromList(ToDo, i) ;
384 movement := TryDependents(sym) ;
395 PROCEDURE DoName (sym: CARDINAL) ;
399 n := GetFullScopeAsmName(sym) ;
408 PROCEDURE DoParamName (sym: CARDINAL) ;
412 n := GetSymName(sym) ;
421 PROCEDURE DoVar (sym: CARDINAL) ;
423 fprintf0(f, 'extern "C" ') ;
424 DoType(GetType(sym)) ;
435 PROCEDURE DoType (sym: CARDINAL) ;
439 DoType(GetType(sym)) ;
443 fprintf0(f, "unsigned int")
449 fprintf0(f, "unsigned int")
452 fprintf0(f, "long long int")
455 fprintf0(f, "long long unsigned int")
461 fprintf0(f, "short unsigned int")
464 fprintf0(f, "short int")
467 fprintf0(f, "double")
470 fprintf0(f, "long double")
476 fprintf0(f, "unsigned int")
479 fprintf0(f, "void *")
482 fprintf0(f, "unsigned char")
485 fprintf0(f, "unsigned char")
488 fprintf0(f, "unsigned int")
497 PROCEDURE DoUnbounded (sym: CARDINAL) ;
502 type := GetType(sym) ;
503 DoType(GetType(type)) ;
504 n := GetSymName(sym) ;
505 fprintf2(f, ' *_m2_address_%a, int _m2_high_%a', n, n)
523 PROCEDURE DoBasicBlock (start, end: CARDINAL) ;
525 IF IsProcedureScope(start)
527 (* skip this basic block, as this will not modify the parameter *)
529 ELSIF IsKnown OR CanGuess
531 (* already resolved *)
536 FirstBasicBlock := FALSE
549 FirstBasicBlock := FALSE
555 IF (rs<=end) AND FirstBasicBlock
561 FirstBasicBlock := FALSE
564 (* read before write *)
566 IF (rs<=end) AND (ws<=end) AND FirstBasicBlock
572 FirstBasicBlock := FALSE
574 (* must be written before read *)
576 IF (rs<=end) AND (ws<=end) AND FirstBasicBlock
582 FirstBasicBlock := FALSE
592 PROCEDURE DetermineParameter (procedure, param: CARDINAL) ;
599 sb := InitScopeBlock(procedure) ;
600 bb := InitBasicBlocks(sb) ;
606 FirstBasicBlock := TRUE ;
607 GetReadQuads(param, RightValue, rs, re) ;
608 GetWriteQuads(param, RightValue, ws, we) ;
609 ForeachBasicBlockDo(bb, DoBasicBlock) ;
610 KillBasicBlocks(bb) ;
612 END DetermineParameter ;
619 PROCEDURE PrintDirection ;
626 fprintf0(f, 'OUTPUT')
634 CalculateVarDirective -
637 PROCEDURE CalculateVarDirective (procedure, param: CARDINAL; annotate: BOOLEAN) ;
641 sym := GetParameterShadowVar(param) ;
644 InternalError ('why did we get here')
646 DetermineParameter(procedure, sym) ;
652 fprintf0(f, ' is known to be an ') ;
656 fprintf0(f, ' is guessed to be an ') ;
659 fprintf0(f, ' is unknown')
663 IF IsKnown OR CanGuess
671 END CalculateVarDirective ;
678 PROCEDURE AnnotateProcedure (sym: CARDINAL) ;
680 son, p, i: CARDINAL ;
683 fprintf0(f, '/* parameter: ') ;
684 p := NoOfParam(sym) ;
688 son := GetNthParam(sym, i) ;
689 IF IsParameterVar(son)
695 CalculateVarDirective(sym, son, TRUE) ;
700 fprintf0(f, ' */\n\n')
701 END AnnotateProcedure ;
708 PROCEDURE DoProcedure (sym: CARDINAL) : BOOLEAN ;
715 fprintf0(f, 'extern "C" ') ;
716 IF GetType(sym)=NulSym
718 fprintf0(f, 'void') ;
725 p := NoOfParam(sym) ;
728 fprintf0(f, 'void') ;
732 son := GetNthParam(sym, i) ;
733 IF IsUnboundedParam(sym, i)
737 DoType(GetType(son)) ;
739 IF IsParameterVar(son)
742 CalculateVarDirective(sym, son, FALSE)
754 fprintf0(f, ');\n') ;
763 PROCEDURE DoWriteSymbol (sym: CARDINAL) ;
767 ELSIF IsSystemType(sym)
771 ELSIF IsProcedure(sym)
775 AnnotateProcedure(sym)
777 ELSIF IsConstString(sym)
779 ELSIF IsConstLit(sym)
781 ELSIF IsVar(sym) AND (GetMode(sym)=ImmediateValue)
794 PROCEDURE DoCheckExported (sym: WORD) ;
796 IF IsExported(mainModule, sym)
800 END DoCheckExported ;
804 IsUnique - returns TRUE if the combination of, n, and, t,
808 PROCEDURE IsUnique (n: Name; t: CARDINAL) : BOOLEAN ;
814 h := HighIndice(uKey) ;
816 p := GetIndice(uKey, i) ;
817 IF (p^.type=t) AND (p^.name=n)
829 PutIndice(uKey, h, p) ;
835 IsTypeUnique - returns TRUE if type, t, has not been entered yet.
838 PROCEDURE IsTypeUnique (t: CARDINAL) : BOOLEAN ;
844 h := HighIndice(uKey) ;
846 p := GetIndice(uKey, i) ;
861 PROCEDURE DoCheckUnbounded (sym: WORD) ;
865 typeUnique: BOOLEAN ;
867 IF IsParameter(sym) AND IsParameterUnbounded(sym)
869 name := GetSymName(sym) ;
870 type := GetType(GetType(sym)) ;
871 typeUnique := IsTypeUnique(type) ;
872 IF IsUnique(name, type)
876 includedArray := TRUE ;
877 fprintf0(f, '%include "carrays.i"\n')
880 fprintf0(f, 'apply (char *STRING, int LENGTH) { (') ;
882 fprintf0(f, ') };\n') ;
885 fprintf0(f, '%array_functions(') ;
889 fprintf0(f, 'Array);\n')
893 END DoCheckUnbounded ;
900 PROCEDURE DoWriteFile (sym: CARDINAL) ;
905 n := GetSymName(sym) ;
906 fprintf0(f, '/* automatically generated by gm2 -fswig */\n') ;
908 fprintf1(f, 'module %a\n\n', n) ;
910 fprintf1(f, 'include exception.i\n\n', n) ;
912 fprintf0(f, 'exception {\n') ;
913 fprintf0(f, ' try {\n') ;
914 fprintf0(f, ' $action\n') ;
915 fprintf0(f, ' } catch (int i) {\n') ;
916 fprintf0(f, ' return NULL;\n') ;
917 fprintf0(f, ' }\n') ;
918 fprintf0(f, '}\n\n') ;
919 ForeachItemInListDo(Done, DoCheckUnbounded) ;
920 fprintf0(f, '\n%{\n') ;
921 ForeachItemInListDo(Done, DoCheckExported) ;
922 fprintf0(f, '%}\n\n') ;
923 ForeachItemInListDo(Done, DoCheckExported)
931 PROCEDURE DoGenerateSwig (sym: CARDINAL) ;
934 name := ConCat (InitStringCharStar (KeyToCharStar (GetSymName (sym))),
935 Mark (InitString ('.i'))) ;
936 f := OpenToWrite (name) ;
937 ForeachExportedDo (sym, DoExported) ;
941 name := KillString (name) ;
947 GenerateSwigFile - if the -fswig option was specified then generate
948 a swig interface file for the main module.
951 PROCEDURE GenerateSwigFile (sym: CARDINAL) ;
957 END GenerateSwigFile ;
968 uKey := InitIndex(1) ;
969 includedArray := FALSE
981 uKey := KillIndex(uKey)