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,
61 GetBasicBlockStart, GetBasicBlockEnd ;
65 UnboundedSig = POINTER TO RECORD
71 includedArray: BOOLEAN ;
73 mainModule : CARDINAL ;
81 DoExported - includes, sym, into the, ToDo, list.
84 PROCEDURE DoExported (sym: CARDINAL) ;
86 IncludeItemIntoList(ToDo, sym)
91 MoveToDone - moves a sym to the, Done, list,
92 providing that it is not already on it.
93 It returns TRUE if the lists were modified.
96 PROCEDURE MoveToDone (sym: CARDINAL) : BOOLEAN ;
98 IF IsItemInList(Done, sym)
101 ELSIF IsItemInList(ToDo, sym)
103 RemoveItemFromList(ToDo, sym) ;
104 IncludeItemIntoList(Done, sym) ;
107 IncludeItemIntoList(Done, sym) ;
113 MoveToToDo - moves a sym to the, ToDo, list,
114 providing that it is not already on it.
115 It returns TRUE if the lists were modified.
118 PROCEDURE MoveToToDo (sym: CARDINAL) : BOOLEAN ;
120 IF IsItemInList(Done, sym)
122 InternalError ('not expecting to get here')
123 ELSIF IsItemInList(ToDo, sym)
127 IncludeItemIntoList(ToDo, sym) ;
134 Trybase - returns TRUE
137 PROCEDURE TryBase (sym: CARDINAL) : BOOLEAN ;
139 IF (sym=Cardinal) OR (sym=Integer) OR (sym=LongInt) OR
140 (sym=LongCard) OR (sym=Char) OR (sym=ShortCard) OR
141 (sym=ShortInt) OR (sym=Real) OR (sym=LongReal) OR
142 (sym=ShortReal) OR (sym=Boolean)
144 RETURN( MoveToDone(sym) )
152 TrySystem - returns TRUE if sym can be moved to the done list.
155 PROCEDURE TrySystem (sym: CARDINAL) : BOOLEAN ;
157 IF (sym=Bitset) OR (sym=Address) OR (sym=Byte) OR (sym=Loc) OR
160 RETURN( MoveToDone(sym) )
168 TryMove - tries to move sym to the done queue as long
172 PROCEDURE TryMove (sym, type: CARDINAL) : BOOLEAN ;
174 IF IsItemInList(Done, type)
194 PROCEDURE TryType (sym: CARDINAL) : BOOLEAN ;
199 type := GetType(sym) ;
200 result := TryDependents(type) ;
201 IF TryMove(sym, type)
214 PROCEDURE TryVar (sym: CARDINAL) : BOOLEAN ;
219 type := GetType(sym) ;
220 result := TryDependents(type) ;
221 IF TryMove(sym, type)
234 PROCEDURE TryProcedure (sym: CARDINAL) : BOOLEAN ;
242 type := GetType(sym) ;
247 IF TryDependents(type)
251 IF NOT IsItemInList(Done, type)
256 p := NoOfParam(sym) ;
259 son := GetNthParam(sym, i) ;
260 IF TryDependents(son)
264 IF NOT IsItemInList(Done, son)
290 PROCEDURE TryUnbounded (sym: CARDINAL) : BOOLEAN ;
295 type := GetType(sym) ;
296 result := TryDependents(type) ;
297 IF TryMove(sym, type)
310 PROCEDURE TryParameter (sym: CARDINAL) : BOOLEAN ;
315 type := GetType(sym) ;
316 result := TryDependents(type) ;
317 IF TryMove(sym, type)
327 TryDependents - returns TRUE if any alteration occurred to any
331 PROCEDURE TryDependents (sym: CARDINAL) : BOOLEAN ;
335 RETURN( TryBase(sym) )
336 ELSIF IsSystemType(sym)
338 RETURN( TrySystem(sym) )
341 RETURN( TryType(sym) )
342 ELSIF IsParameter(sym)
344 RETURN( TryParameter(sym) )
345 ELSIF IsProcedure(sym)
347 RETURN( TryProcedure(sym) )
348 ELSIF IsConstString(sym)
350 RETURN( MoveToDone(sym) )
351 ELSIF IsConstLit(sym)
353 RETURN( MoveToDone(sym) )
354 ELSIF IsVar(sym) AND (GetMode(sym)=ImmediateValue)
356 RETURN( MoveToDone(sym) )
359 RETURN( TryVar(sym) )
360 ELSIF IsUnbounded(sym)
362 RETURN( TryUnbounded(sym) )
370 DoResolveOrder - resolves the declaration order for swig (C).
373 PROCEDURE DoResolveOrder ;
380 n := NoOfItemsInList(ToDo) ;
383 WHILE (i<=n) AND (NOT movement) DO
384 sym := GetItemFromList(ToDo, i) ;
385 movement := TryDependents(sym) ;
396 PROCEDURE DoName (sym: CARDINAL) ;
400 n := GetFullScopeAsmName(sym) ;
409 PROCEDURE DoParamName (sym: CARDINAL) ;
413 n := GetSymName(sym) ;
422 PROCEDURE DoVar (sym: CARDINAL) ;
424 fprintf0(f, 'extern "C" ') ;
425 DoType(GetType(sym)) ;
436 PROCEDURE DoType (sym: CARDINAL) ;
440 DoType(GetType(sym)) ;
444 fprintf0(f, "unsigned int")
450 fprintf0(f, "unsigned int")
453 fprintf0(f, "long long int")
456 fprintf0(f, "long long unsigned int")
462 fprintf0(f, "short unsigned int")
465 fprintf0(f, "short int")
468 fprintf0(f, "double")
471 fprintf0(f, "long double")
477 fprintf0(f, "unsigned int")
480 fprintf0(f, "void *")
483 fprintf0(f, "unsigned char")
486 fprintf0(f, "unsigned char")
489 fprintf0(f, "unsigned int")
498 PROCEDURE DoUnbounded (sym: CARDINAL) ;
503 type := GetType(sym) ;
504 DoType(GetType(type)) ;
505 n := GetSymName(sym) ;
506 fprintf2(f, ' *_m2_address_%a, int _m2_high_%a', n, n)
524 PROCEDURE DoBasicBlock (bb: BasicBlock) ;
526 start, end: CARDINAL ;
528 start := GetBasicBlockStart (bb) ;
529 end := GetBasicBlockEnd (bb) ;
530 IF IsProcedureScope(start)
532 (* skip this basic block, as this will not modify the parameter *)
534 ELSIF IsKnown OR CanGuess
536 (* already resolved *)
541 FirstBasicBlock := FALSE
554 FirstBasicBlock := FALSE
560 IF (rs<=end) AND FirstBasicBlock
566 FirstBasicBlock := FALSE
569 (* read before write *)
571 IF (rs<=end) AND (ws<=end) AND FirstBasicBlock
577 FirstBasicBlock := FALSE
579 (* must be written before read *)
581 IF (rs<=end) AND (ws<=end) AND FirstBasicBlock
587 FirstBasicBlock := FALSE
597 PROCEDURE DetermineParameter (procedure, param: CARDINAL) ;
604 sb := InitScopeBlock(procedure) ;
605 bb := InitBasicBlocks(sb) ;
611 FirstBasicBlock := TRUE ;
612 GetReadQuads(param, RightValue, rs, re) ;
613 GetWriteQuads(param, RightValue, ws, we) ;
614 ForeachBasicBlockDo(bb, DoBasicBlock) ;
615 KillBasicBlocks(bb) ;
617 END DetermineParameter ;
624 PROCEDURE PrintDirection ;
631 fprintf0(f, 'OUTPUT')
639 CalculateVarDirective -
642 PROCEDURE CalculateVarDirective (procedure, param: CARDINAL; annotate: BOOLEAN) ;
646 sym := GetParameterShadowVar(param) ;
649 InternalError ('why did we get here')
651 DetermineParameter(procedure, sym) ;
657 fprintf0(f, ' is known to be an ') ;
661 fprintf0(f, ' is guessed to be an ') ;
664 fprintf0(f, ' is unknown')
668 IF IsKnown OR CanGuess
676 END CalculateVarDirective ;
683 PROCEDURE AnnotateProcedure (sym: CARDINAL) ;
685 son, p, i: CARDINAL ;
688 fprintf0(f, '/* parameter: ') ;
689 p := NoOfParam(sym) ;
693 son := GetNthParam(sym, i) ;
694 IF IsParameterVar(son)
700 CalculateVarDirective(sym, son, TRUE) ;
705 fprintf0(f, ' */\n\n')
706 END AnnotateProcedure ;
713 PROCEDURE DoProcedure (sym: CARDINAL) : BOOLEAN ;
720 fprintf0(f, 'extern "C" ') ;
721 IF GetType(sym)=NulSym
723 fprintf0(f, 'void') ;
730 p := NoOfParam(sym) ;
733 fprintf0(f, 'void') ;
737 son := GetNthParam(sym, i) ;
738 IF IsUnboundedParam(sym, i)
742 DoType(GetType(son)) ;
744 IF IsParameterVar(son)
747 CalculateVarDirective(sym, son, FALSE)
759 fprintf0(f, ');\n') ;
768 PROCEDURE DoWriteSymbol (sym: CARDINAL) ;
772 ELSIF IsSystemType(sym)
776 ELSIF IsProcedure(sym)
780 AnnotateProcedure(sym)
782 ELSIF IsConstString(sym)
784 ELSIF IsConstLit(sym)
786 ELSIF IsVar(sym) AND (GetMode(sym)=ImmediateValue)
799 PROCEDURE DoCheckExported (sym: WORD) ;
801 IF IsExported(mainModule, sym)
805 END DoCheckExported ;
809 IsUnique - returns TRUE if the combination of, n, and, t,
813 PROCEDURE IsUnique (n: Name; t: CARDINAL) : BOOLEAN ;
819 h := HighIndice(uKey) ;
821 p := GetIndice(uKey, i) ;
822 IF (p^.type=t) AND (p^.name=n)
834 PutIndice(uKey, h, p) ;
840 IsTypeUnique - returns TRUE if type, t, has not been entered yet.
843 PROCEDURE IsTypeUnique (t: CARDINAL) : BOOLEAN ;
849 h := HighIndice(uKey) ;
851 p := GetIndice(uKey, i) ;
866 PROCEDURE DoCheckUnbounded (sym: WORD) ;
870 typeUnique: BOOLEAN ;
872 IF IsParameter(sym) AND IsParameterUnbounded(sym)
874 name := GetSymName(sym) ;
875 type := GetType(GetType(sym)) ;
876 typeUnique := IsTypeUnique(type) ;
877 IF IsUnique(name, type)
881 includedArray := TRUE ;
882 fprintf0(f, '%include "carrays.i"\n')
885 fprintf0(f, 'apply (char *STRING, int LENGTH) { (') ;
887 fprintf0(f, ') };\n') ;
890 fprintf0(f, '%array_functions(') ;
894 fprintf0(f, 'Array);\n')
898 END DoCheckUnbounded ;
905 PROCEDURE DoWriteFile (sym: CARDINAL) ;
910 n := GetSymName(sym) ;
911 fprintf0(f, '/* automatically generated by gm2 -fswig */\n') ;
913 fprintf1(f, 'module %a\n\n', n) ;
915 fprintf1(f, 'include exception.i\n\n', n) ;
917 fprintf0(f, 'exception {\n') ;
918 fprintf0(f, ' try {\n') ;
919 fprintf0(f, ' $action\n') ;
920 fprintf0(f, ' } catch (int i) {\n') ;
921 fprintf0(f, ' return NULL;\n') ;
922 fprintf0(f, ' }\n') ;
923 fprintf0(f, '}\n\n') ;
924 ForeachItemInListDo(Done, DoCheckUnbounded) ;
925 fprintf0(f, '\n%{\n') ;
926 ForeachItemInListDo(Done, DoCheckExported) ;
927 fprintf0(f, '%}\n\n') ;
928 ForeachItemInListDo(Done, DoCheckExported)
936 PROCEDURE DoGenerateSwig (sym: CARDINAL) ;
939 name := ConCat (InitStringCharStar (KeyToCharStar (GetSymName (sym))),
940 Mark (InitString ('.i'))) ;
941 f := OpenToWrite (name) ;
942 ForeachExportedDo (sym, DoExported) ;
946 name := KillString (name) ;
952 GenerateSwigFile - if the -fswig option was specified then generate
953 a swig interface file for the main module.
956 PROCEDURE GenerateSwigFile (sym: CARDINAL) ;
962 END GenerateSwigFile ;
973 uKey := InitIndex(1) ;
974 includedArray := FALSE
986 uKey := KillIndex(uKey)