mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
1331 lines
35 KiB
Modula-2
1331 lines
35 KiB
Modula-2
(* M2Comp.mod continually calls the compiler for every source file.
|
|
|
|
Copyright (C) 2001-2026 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 M2Comp ;
|
|
|
|
|
|
FROM M2Pass IMPORT SetPassToPass0, SetPassToPass1, SetPassToPass2, SetPassToPassC,
|
|
SetPassToPass3, SetPassToNoPass, SetPassToPassHidden ;
|
|
|
|
FROM M2Reserved IMPORT toktype ;
|
|
FROM M2Search IMPORT FindSourceDefFile, FindSourceModFile ;
|
|
FROM M2Code IMPORT Code ;
|
|
|
|
FROM M2LexBuf IMPORT OpenSource, CloseSource, ResetForNewPass, currenttoken, GetToken,
|
|
ReInitialize, currentstring, GetTokenNo, BuiltinTokenNo,
|
|
UnknownTokenNo ;
|
|
|
|
FROM M2FileName IMPORT CalculateFileName ;
|
|
FROM M2Preprocess IMPORT PreprocessModule, MakeSaveTempsFileNameExt, OnExitDelete ;
|
|
FROM libc IMPORT exit ;
|
|
|
|
FROM M2Error IMPORT ErrorStringAt, ErrorStringAt2, ErrorStringsAt2,
|
|
WriteFormat0, FlushErrors, FlushWarnings, ResetErrorScope ;
|
|
|
|
FROM M2MetaError IMPORT MetaErrorString0, MetaErrorString1, MetaError0, MetaError1,
|
|
MetaString0 ;
|
|
|
|
FROM FormatStrings IMPORT Sprintf1 ;
|
|
FROM P0SymBuild IMPORT P0Init, P1Init ;
|
|
FROM M2Debug IMPORT Assert ;
|
|
|
|
IMPORT m2flex ;
|
|
IMPORT m2block ;
|
|
IMPORT P0SyntaxCheck ;
|
|
IMPORT P1Build ;
|
|
IMPORT P2Build ;
|
|
IMPORT PCBuild ;
|
|
IMPORT P3Build ;
|
|
IMPORT PHBuild ;
|
|
IMPORT PCSymBuild ;
|
|
IMPORT DynamicStrings ;
|
|
IMPORT M2Diagnostic ;
|
|
|
|
FROM M2Batch IMPORT GetSource, GetModuleNo, GetDefinitionModuleFile, GetModuleFile,
|
|
AssociateModule, AssociateDefinition, MakeImplementationSource,
|
|
MakeProgramSource ;
|
|
|
|
FROM SymbolTable IMPORT GetSymName, IsDefImp, NulSym,
|
|
IsHiddenTypeDeclared, GetFirstUsed, GetMainModule, SetMainModule,
|
|
ResolveConstructorTypes, SanityCheckConstants, IsDefinitionForC,
|
|
IsBuiltinInModule, PutModLink, IsDefLink, IsModLink, PutLibName,
|
|
GetModuleDefImportStatementList, GetModuleModImportStatementList,
|
|
GetImportModule, IsImportStatement, IsImport,
|
|
GetImportStatementList ;
|
|
|
|
FROM M2Search IMPORT FindSourceDefFile ;
|
|
FROM M2Diagnostic IMPORT Diagnostic, InitMemDiagnostic, MemIncr, MemSet ;
|
|
|
|
FROM FIO IMPORT File, StdErr, StdOut, Close, EOF, IsNoError, WriteLine,
|
|
WriteChar, FlushOutErr ;
|
|
|
|
FROM SFIO IMPORT WriteS, OpenToRead, OpenToWrite, ReadS, WriteS ;
|
|
FROM NameKey IMPORT Name, GetKey, KeyToCharStar, makekey ;
|
|
FROM M2Printf IMPORT fprintf0, fprintf1 ;
|
|
FROM M2Quiet IMPORT qprintf0, qprintf1, qprintf2 ;
|
|
|
|
FROM M2Options IMPORT Verbose, GetM2Prefix, GetM, GetMM, GetDepTarget, GetMF, GetMP,
|
|
GetObj, PPonly, Quiet, WholeProgram, GetMD, GetMMD,
|
|
ExtendedOpaque, GenModuleList, TimeReport, MemReport ;
|
|
|
|
FROM PathName IMPORT DumpPathName ;
|
|
FROM Lists IMPORT List, NoOfItemsInList, GetItemFromList ;
|
|
FROM Indexing IMPORT Index, InitIndex, KillIndex, GetIndice, PutIndice, HighIndice ;
|
|
|
|
FROM DynamicStrings IMPORT String, InitString, KillString, InitStringCharStar,
|
|
Dup, Mark, EqualArray, string, Length, ConCat, ConCatChar,
|
|
InitStringChar, RIndex, Slice, Equal, RemoveWhitePrefix ;
|
|
|
|
|
|
|
|
CONST
|
|
Debugging = FALSE ;
|
|
|
|
VAR
|
|
ModuleType : (None, Definition, Implementation, Program) ;
|
|
DepContent : Index ;
|
|
DepOutput : String ;
|
|
|
|
|
|
(*
|
|
CompilingDefinitionModule - returns true if the current module being
|
|
compiled is a definition module.
|
|
*)
|
|
|
|
PROCEDURE CompilingDefinitionModule() : BOOLEAN ;
|
|
BEGIN
|
|
RETURN( ModuleType=Definition )
|
|
END CompilingDefinitionModule ;
|
|
|
|
|
|
(*
|
|
CompilingImplementationModule - returns true if the current module being
|
|
compiled is an implementation module.
|
|
*)
|
|
|
|
PROCEDURE CompilingImplementationModule() : BOOLEAN ;
|
|
BEGIN
|
|
RETURN( ModuleType=Implementation )
|
|
END CompilingImplementationModule ;
|
|
|
|
|
|
(*
|
|
CompilingProgramModule - returns true if the current module being
|
|
compiled is a program module.
|
|
*)
|
|
|
|
PROCEDURE CompilingProgramModule() : BOOLEAN ;
|
|
BEGIN
|
|
RETURN( ModuleType=Program )
|
|
END CompilingProgramModule ;
|
|
|
|
|
|
(*
|
|
NeedToParseImplementation -
|
|
*)
|
|
|
|
PROCEDURE NeedToParseImplementation (sym: CARDINAL) : BOOLEAN ;
|
|
BEGIN
|
|
RETURN (IsDefImp(sym) AND IsHiddenTypeDeclared(sym) AND ExtendedOpaque) OR
|
|
(IsDefImp(sym) AND IsBuiltinInModule(sym)) OR
|
|
(WholeProgram AND (NOT IsDefinitionForC(sym)))
|
|
END NeedToParseImplementation ;
|
|
|
|
|
|
(*
|
|
GenerateDefDependency - generate a single dependency for the definition module
|
|
providing that it can be found and is not blocked by -MM.
|
|
*)
|
|
|
|
PROCEDURE GenerateDefDependency (module: CARDINAL) ;
|
|
VAR
|
|
stem,
|
|
fullpath,
|
|
named : String ;
|
|
BEGIN
|
|
stem := InitStringCharStar (KeyToCharStar (GetSymName (module))) ;
|
|
named := NIL ;
|
|
IF FindSourceDefFile (stem, fullpath, named)
|
|
THEN
|
|
IF EqualArray (named, '') OR (NOT GetMM ())
|
|
THEN
|
|
MergeDep (DepContent, fullpath)
|
|
ELSE
|
|
fullpath := KillString (fullpath)
|
|
END
|
|
END ;
|
|
stem := KillString (stem) ;
|
|
named := KillString (named)
|
|
END GenerateDefDependency ;
|
|
|
|
|
|
(*
|
|
GenerateDependenciesFromImport - lookup the module associated with the import
|
|
and call GenerateDefDependency.
|
|
*)
|
|
|
|
PROCEDURE GenerateDependenciesFromImport (import: CARDINAL) ;
|
|
VAR
|
|
module : CARDINAL ;
|
|
BEGIN
|
|
Assert (IsImport (import)) ;
|
|
module := GetImportModule (import) ;
|
|
GenerateDefDependency (module)
|
|
END GenerateDependenciesFromImport ;
|
|
|
|
|
|
(*
|
|
GenerateDependenciesFromList - iterative over the import lists and for
|
|
each module issue a dependency.
|
|
*)
|
|
|
|
PROCEDURE GenerateDependenciesFromList (dep: List) ;
|
|
VAR
|
|
importList: List ;
|
|
import : CARDINAL ;
|
|
i, n, j, m: CARDINAL ;
|
|
BEGIN
|
|
n := NoOfItemsInList (dep) ;
|
|
i := 1 ;
|
|
WHILE i <= n DO
|
|
import := GetItemFromList (dep, i) ;
|
|
IF IsImportStatement (import)
|
|
THEN
|
|
importList := GetImportStatementList (import) ;
|
|
j := 1 ;
|
|
m := NoOfItemsInList (importList) ;
|
|
WHILE j <= m DO
|
|
import := GetItemFromList (importList, j) ;
|
|
GenerateDependenciesFromImport (import) ;
|
|
INC (j)
|
|
END
|
|
ELSE
|
|
GenerateDependenciesFromImport (import)
|
|
END ;
|
|
INC (i)
|
|
END
|
|
END GenerateDependenciesFromList ;
|
|
|
|
|
|
(*
|
|
GenerateDependencies - generate a list of dependencies for the main module where
|
|
the source code is found in sourcefile.
|
|
*)
|
|
|
|
PROCEDURE GenerateDependencies ;
|
|
BEGIN
|
|
IF IsDefImp (GetMainModule ())
|
|
THEN
|
|
GenerateDependenciesFromList (GetModuleDefImportStatementList (GetMainModule ())) ;
|
|
GenerateDefDependency (GetMainModule ())
|
|
END ;
|
|
GenerateDependenciesFromList (GetModuleModImportStatementList (GetMainModule ())) ;
|
|
WriteDepContents (DepOutput, DepContent)
|
|
END GenerateDependencies ;
|
|
|
|
|
|
(*
|
|
Compile - compile file, s, using a 5 pass technique.
|
|
*)
|
|
|
|
PROCEDURE Compile (s: String) ;
|
|
BEGIN
|
|
DoPass0 (s) ;
|
|
FlushWarnings ; FlushErrors ;
|
|
ResetForNewPass ; ResetErrorScope ;
|
|
qprintf0('Pass 1: scopes, enumerated types, imports and exports\n') ;
|
|
DoPass1 ;
|
|
FlushWarnings ; FlushErrors ;
|
|
IF GetM () OR GetMM ()
|
|
THEN
|
|
GenerateDependencies
|
|
END ;
|
|
IF NOT PPonly
|
|
THEN
|
|
qprintf0('Pass 2: constants and types\n') ;
|
|
ResetForNewPass ; ResetErrorScope ;
|
|
DoPass2 ;
|
|
FlushWarnings ; FlushErrors ;
|
|
qprintf0('Pass C: aggregate constants\n') ;
|
|
ResetForNewPass ; ResetErrorScope ;
|
|
DoPassC ;
|
|
FlushWarnings ; FlushErrors ;
|
|
qprintf0('Pass 3: quadruple generation\n') ;
|
|
ResetForNewPass ; ResetErrorScope ;
|
|
DoPass3 ;
|
|
FlushWarnings ; FlushErrors ;
|
|
qprintf0('Pass 4: gcc tree generation\n') ;
|
|
Code ;
|
|
FlushWarnings ; FlushErrors
|
|
END
|
|
END Compile ;
|
|
|
|
|
|
(*
|
|
compile - compile the filename.
|
|
*)
|
|
|
|
PROCEDURE compile (filename: ADDRESS) ;
|
|
VAR
|
|
f, s: String ;
|
|
BEGIN
|
|
M2Diagnostic.Configure (TimeReport, MemReport) ;
|
|
f := InitStringCharStar (filename) ;
|
|
Compile (f) ;
|
|
f := KillString (f) ;
|
|
PopulateResource ;
|
|
IF TimeReport OR MemReport
|
|
THEN
|
|
s := WriteS (StdOut, M2Diagnostic.Generate (FALSE)) ;
|
|
FlushOutErr ;
|
|
s := KillString (s)
|
|
END
|
|
END compile ;
|
|
|
|
|
|
(*
|
|
PopulateResource -
|
|
*)
|
|
|
|
PROCEDURE PopulateResource ;
|
|
VAR
|
|
StatsMemDiag: Diagnostic ;
|
|
BEGIN
|
|
IF MemReport
|
|
THEN
|
|
StatsMemDiag
|
|
:= InitMemDiagnostic
|
|
('M2Comp:statistics',
|
|
'total source lines {1d} total constants {2d} total types {3d}') ;
|
|
MemSet (StatsMemDiag, 1, m2flex.GetTotalLines ()) ;
|
|
MemSet (StatsMemDiag, 2, m2block.GetTotalConstants ()) ;
|
|
MemSet (StatsMemDiag, 3, m2block.GetGlobalTypes ())
|
|
END
|
|
END PopulateResource ;
|
|
|
|
|
|
(*
|
|
ExamineHeader - examines up until the ';', '[' or eof and determines if the source file
|
|
is a program, implementation/definition module.
|
|
*)
|
|
|
|
PROCEDURE ExamineHeader (VAR name: ADDRESS; VAR isdefimp, module: BOOLEAN) ;
|
|
BEGIN
|
|
(* Stop if we see one of eof ';' '['. *)
|
|
WHILE (currenttoken#eoftok) AND
|
|
(currenttoken#semicolontok) AND (currenttoken#lsbratok) DO
|
|
IF name = NIL
|
|
THEN
|
|
IF (currenttoken=implementationtok) OR (currenttoken=definitiontok)
|
|
THEN
|
|
isdefimp := TRUE ;
|
|
GetToken
|
|
END ;
|
|
IF currenttoken=moduletok
|
|
THEN
|
|
module := TRUE ;
|
|
GetToken ;
|
|
IF currenttoken=identtok
|
|
THEN
|
|
name := currentstring
|
|
END
|
|
END ;
|
|
END ;
|
|
GetToken
|
|
END ;
|
|
END ExamineHeader ;
|
|
|
|
|
|
(*
|
|
ExamineCompilationUnit - opens the source file to obtain the module name and kind of module.
|
|
*)
|
|
|
|
PROCEDURE ExamineCompilationUnit () : CARDINAL ;
|
|
VAR
|
|
Message : String ;
|
|
name : ADDRESS ;
|
|
module,
|
|
isdefimp: BOOLEAN ;
|
|
BEGIN
|
|
name := NIL ;
|
|
isdefimp := FALSE ; (* default to program module *)
|
|
module := FALSE ; (* Seen module keyword? *)
|
|
ExamineHeader (name, isdefimp, module) ;
|
|
IF name = NIL
|
|
THEN
|
|
IF module
|
|
THEN
|
|
Message := MetaString0 (InitString ('no {%kMODULE} keyword seen'))
|
|
ELSE
|
|
Message := MetaString0 (InitString ('no module ident seen'))
|
|
END ;
|
|
m2flex.M2Error (string (Message)) ;
|
|
exit (1)
|
|
ELSE
|
|
(* The token used is will be overwritten when P0 is underway.
|
|
At this point we are determining the module kind and the tokens
|
|
read will be discarded (see ReInitialize below). *)
|
|
IF isdefimp
|
|
THEN
|
|
RETURN MakeImplementationSource (BuiltinTokenNo, makekey (name))
|
|
ELSE
|
|
RETURN MakeProgramSource (BuiltinTokenNo, makekey (name))
|
|
END
|
|
END
|
|
END ExamineCompilationUnit ;
|
|
|
|
|
|
(*
|
|
PeepInto - peeps into source, s, and initializes a definition/implementation or
|
|
program module accordingly.
|
|
*)
|
|
|
|
PROCEDURE PeepInto (s: String) ;
|
|
VAR
|
|
mainModule: CARDINAL ;
|
|
BEGIN
|
|
IF OpenSource (s)
|
|
THEN
|
|
mainModule := ExamineCompilationUnit () ;
|
|
IF mainModule # NulSym
|
|
THEN
|
|
SetMainModule (mainModule)
|
|
END ;
|
|
CloseSource ;
|
|
ReInitialize
|
|
ELSE
|
|
fprintf1 (StdErr, 'failed to open %s\n', s) ;
|
|
exit (1)
|
|
END
|
|
END PeepInto ;
|
|
|
|
|
|
(*
|
|
qprintLibName - print the libname.
|
|
*)
|
|
|
|
PROCEDURE qprintLibName (LibName: String) ;
|
|
BEGIN
|
|
IF (LibName # NIL) AND (NOT EqualArray (LibName, ''))
|
|
THEN
|
|
qprintf1 (' [%s]', LibName)
|
|
END
|
|
END qprintLibName ;
|
|
|
|
|
|
(*
|
|
CreateFileStem - create a stem using the template LibName_ModuleName.
|
|
*)
|
|
|
|
PROCEDURE CreateFileStem (SymName, LibName: String) : String ;
|
|
BEGIN
|
|
IF Length (LibName) > 0
|
|
THEN
|
|
RETURN ConCat (Dup (LibName), ConCat (InitStringChar ('_'), SymName))
|
|
ELSE
|
|
RETURN SymName
|
|
END
|
|
END CreateFileStem ;
|
|
|
|
|
|
(*
|
|
Return basename of path. CutExt determines whether the .extension
|
|
should be removed.
|
|
*)
|
|
|
|
PROCEDURE BaseName (Path: String; CutExt: BOOLEAN) : String ;
|
|
VAR
|
|
ext,
|
|
basename: INTEGER ;
|
|
BEGIN
|
|
basename := RIndex (Path, '/', 0) ;
|
|
IF basename = -1
|
|
THEN
|
|
basename := 0
|
|
ELSE
|
|
basename := basename + 1
|
|
END ;
|
|
IF CutExt
|
|
THEN
|
|
ext := RIndex (Path, '.', 0) ;
|
|
IF ext=-1
|
|
THEN
|
|
ext := 0
|
|
END
|
|
ELSE
|
|
ext := 0
|
|
END ;
|
|
RETURN Slice (Path, basename, ext)
|
|
END BaseName ;
|
|
|
|
|
|
(*
|
|
IsLibrary - return TRUE if line contains a library module.
|
|
*)
|
|
|
|
PROCEDURE IsLibrary (line: String) : BOOLEAN ;
|
|
VAR
|
|
moduleName,
|
|
libname, filename: String ;
|
|
result : BOOLEAN ;
|
|
BEGIN
|
|
result := FALSE ;
|
|
moduleName := BaseName (line, TRUE) ;
|
|
filename := NIL ;
|
|
libname := NIL ;
|
|
IF FindSourceDefFile (moduleName, filename, libname)
|
|
THEN
|
|
moduleName := KillString (moduleName) ;
|
|
IF Length (libname) > 0
|
|
THEN
|
|
moduleName := BaseName (line, FALSE) ;
|
|
line := BaseName (line, FALSE) ;
|
|
result := Equal (line, moduleName) ;
|
|
line := KillString (line) ;
|
|
END
|
|
END ;
|
|
libname := KillString (libname) ;
|
|
filename := KillString (filename) ;
|
|
moduleName := KillString (moduleName) ;
|
|
RETURN result
|
|
END IsLibrary ;
|
|
|
|
|
|
(*
|
|
IsUnique - return TRUE if line is unique in array content.
|
|
*)
|
|
|
|
PROCEDURE IsUnique (content: Index; line: String) : BOOLEAN ;
|
|
VAR
|
|
high, i: CARDINAL ;
|
|
BEGIN
|
|
high := HighIndice (content) ;
|
|
i := 1 ;
|
|
WHILE i <= high DO
|
|
IF Equal (line, GetIndice (content, i))
|
|
THEN
|
|
RETURN FALSE
|
|
END ;
|
|
INC (i)
|
|
END ;
|
|
RETURN TRUE
|
|
END IsUnique ;
|
|
|
|
|
|
(*
|
|
Append - append line to array content.
|
|
*)
|
|
|
|
PROCEDURE Append (content: Index; line: String) ;
|
|
VAR
|
|
high: CARDINAL ;
|
|
BEGIN
|
|
high := HighIndice (content) ;
|
|
PutIndice (content, high+1, line)
|
|
END Append ;
|
|
|
|
|
|
(*
|
|
MergeDep - if line is unique in array content then append.
|
|
Check to see (and ignore) if line is a library module and -MM
|
|
is present.
|
|
*)
|
|
|
|
PROCEDURE MergeDep (content: Index; line: String) ;
|
|
BEGIN
|
|
line := RemoveWhitePrefix (line) ;
|
|
IF (NOT EqualArray (line, "\")) AND (Length (line) > 0)
|
|
THEN
|
|
(* Ignore if -MM and is a library module. *)
|
|
IF NOT (GetMM () AND IsLibrary (line))
|
|
THEN
|
|
IF IsUnique (content, line)
|
|
THEN
|
|
Append (content, line)
|
|
END
|
|
END
|
|
END
|
|
END MergeDep ;
|
|
|
|
|
|
(*
|
|
splitLine - split a line into words separated by spaces
|
|
and call MergeDep on each word.
|
|
*)
|
|
|
|
PROCEDURE splitLine (content: Index; line: String) ;
|
|
VAR
|
|
word : String ;
|
|
space: INTEGER ;
|
|
BEGIN
|
|
REPEAT
|
|
line := RemoveWhitePrefix (line) ;
|
|
space := DynamicStrings.Index (line, ' ', 0) ;
|
|
IF space > 0
|
|
THEN
|
|
word := Slice (line, 0, space) ;
|
|
word := RemoveWhitePrefix (word) ;
|
|
IF Length (word) > 0
|
|
THEN
|
|
MergeDep (content, word)
|
|
END ;
|
|
line := Slice (line, space, 0) ;
|
|
ELSIF space < 0
|
|
THEN
|
|
MergeDep (content, line)
|
|
END
|
|
UNTIL space <= 0
|
|
END splitLine ;
|
|
|
|
|
|
(*
|
|
MergeDeps - foreach dependency in ChildDep do
|
|
add dependency to ChildDep if not already present.
|
|
ignore all ChildDep if -MM and libname # "".
|
|
*)
|
|
|
|
PROCEDURE MergeDeps (content: Index; ChildDep, LibName: String) ;
|
|
VAR
|
|
line: String ;
|
|
in : File ;
|
|
BEGIN
|
|
IF (content # NIL) AND (NOT (GetMM () AND (Length (LibName) > 0)))
|
|
THEN
|
|
in := OpenToRead (ChildDep) ;
|
|
IF IsNoError (in)
|
|
THEN
|
|
line := ReadS (in) ; (* Skip over first line containing the module object. *)
|
|
WHILE NOT EOF (in) DO
|
|
line := ReadS (in) ;
|
|
splitLine (content, line)
|
|
END
|
|
END ;
|
|
Close (in)
|
|
END
|
|
END MergeDeps ;
|
|
|
|
|
|
(*
|
|
GetRuleTarget - return the rule target which is derived from the -MT arg
|
|
or -o arg or filename.mod.
|
|
*)
|
|
|
|
PROCEDURE GetRuleTarget (filename: String) : String ;
|
|
BEGIN
|
|
IF GetDepTarget () # NIL
|
|
THEN
|
|
RETURN InitStringCharStar (GetDepTarget ())
|
|
ELSIF GetMF () # NIL
|
|
THEN
|
|
RETURN InitStringCharStar (GetMF ())
|
|
ELSE
|
|
RETURN ConCat (BaseName (filename, TRUE), InitString ('.o'))
|
|
END
|
|
END GetRuleTarget ;
|
|
|
|
|
|
(*
|
|
ReadDepContents - reads the contents of file dep into a dynamic array
|
|
and return the array. The file will be split into words
|
|
and each word stored as an entry in the array.
|
|
*)
|
|
|
|
PROCEDURE ReadDepContents (filename, dep: String) : Index ;
|
|
VAR
|
|
content: Index ;
|
|
line : String ;
|
|
in : File ;
|
|
BEGIN
|
|
content := NIL ;
|
|
IF GetM () OR GetMM ()
|
|
THEN
|
|
in := OpenToRead (dep) ;
|
|
(* The file might not be created (if -MD or -MMD is used as these options
|
|
operate without preprocessing) in which case we create an dynamic
|
|
array with the source filename and target. *)
|
|
content := InitIndex (1) ;
|
|
IF GetMD () OR GetMMD () OR (NOT IsNoError (in))
|
|
THEN
|
|
(* No preprocessing done therefore create first two lines using
|
|
target and source. *)
|
|
PutIndice (content, 1, ConCatChar (GetRuleTarget (filename), ':')) ;
|
|
PutIndice (content, 2, Dup (filename))
|
|
ELSE
|
|
(* Preprocessing (using cc1) has created one for us, so we read it. *)
|
|
WHILE NOT EOF (in) DO
|
|
line := ReadS (in) ;
|
|
splitLine (content, line)
|
|
END
|
|
END ;
|
|
Close (in)
|
|
END ;
|
|
RETURN content
|
|
END ReadDepContents ;
|
|
|
|
|
|
(*
|
|
WriteDep - write the dependencies and target to file out.
|
|
*)
|
|
|
|
PROCEDURE WriteDep (contents: Index; out: File) ;
|
|
VAR
|
|
i, h: CARDINAL ;
|
|
line: String ;
|
|
BEGIN
|
|
i := 1 ;
|
|
h := HighIndice (contents) ;
|
|
WHILE i <= h DO
|
|
line := GetIndice (contents, i) ;
|
|
line := RemoveWhitePrefix (line) ;
|
|
IF Length (line) > 0
|
|
THEN
|
|
IF i = 1
|
|
THEN
|
|
(* First line is always the target. *)
|
|
IF GetDepTarget () # NIL
|
|
THEN
|
|
line := ConCatChar (InitStringCharStar (GetDepTarget ()), ':')
|
|
END
|
|
ELSIF i > 1
|
|
THEN
|
|
WriteChar (out, ' ')
|
|
END ;
|
|
line := WriteS (out, line) ;
|
|
IF i < h
|
|
THEN
|
|
WriteChar (out, ' ') ;
|
|
WriteChar (out, '\')
|
|
END ;
|
|
WriteLine (out)
|
|
END ;
|
|
INC (i)
|
|
END
|
|
END WriteDep ;
|
|
|
|
|
|
(*
|
|
WritePhonyDep - write the dependencies and target to file out.
|
|
*)
|
|
|
|
PROCEDURE WritePhonyDep (contents: Index; out: File) ;
|
|
VAR
|
|
i, h: CARDINAL ;
|
|
line: String ;
|
|
BEGIN
|
|
(* The first line is always the target and the second line is always
|
|
the top level source file. *)
|
|
i := 3 ;
|
|
h := HighIndice (contents) ;
|
|
WHILE i <= h DO
|
|
line := GetIndice (contents, i) ;
|
|
line := RemoveWhitePrefix (line) ;
|
|
IF Length (line) > 0
|
|
THEN
|
|
line := WriteS (out, line) ;
|
|
WriteChar (out, ':') ;
|
|
WriteLine (out)
|
|
END ;
|
|
INC (i)
|
|
END
|
|
END WritePhonyDep ;
|
|
|
|
|
|
(*
|
|
WriteDepContents - write the dynamic array to filename dep (or StdOut) if
|
|
the GetMF file is NIL.
|
|
*)
|
|
|
|
PROCEDURE WriteDepContents (dep: String; contents: Index) ;
|
|
VAR
|
|
out: File ;
|
|
BEGIN
|
|
IF (contents # NIL) AND (GetM () OR GetMM ())
|
|
THEN
|
|
IF GetMF () = NIL
|
|
THEN
|
|
out := StdOut ;
|
|
dep := OnExitDelete (dep)
|
|
ELSE
|
|
out := OpenToWrite (dep)
|
|
END ;
|
|
IF IsNoError (out)
|
|
THEN
|
|
WriteDep (contents, out) ;
|
|
IF GetMP ()
|
|
THEN
|
|
WritePhonyDep (contents, out)
|
|
END
|
|
END ;
|
|
IF GetMF () = NIL
|
|
THEN
|
|
FlushOutErr
|
|
ELSE
|
|
Close (out) ;
|
|
END ;
|
|
contents := KillIndex (contents)
|
|
END
|
|
END WriteDepContents ;
|
|
|
|
|
|
(*
|
|
CreateDepFilename - return a dependency filename associated with filename or use GetMF.
|
|
*)
|
|
|
|
PROCEDURE CreateDepFilename (filename: String) : String ;
|
|
VAR
|
|
depfile: String ;
|
|
BEGIN
|
|
IF GetMF () = NIL
|
|
THEN
|
|
depfile := MakeSaveTempsFileNameExt (filename, InitString ('.d')) ;
|
|
RETURN OnExitDelete (depfile)
|
|
ELSE
|
|
RETURN InitStringCharStar (GetMF ())
|
|
END
|
|
END CreateDepFilename ;
|
|
|
|
|
|
(*
|
|
Pass0CheckDef -
|
|
*)
|
|
|
|
PROCEDURE Pass0CheckDef (sym: CARDINAL) : BOOLEAN ;
|
|
VAR
|
|
ChildDep,
|
|
SymName,
|
|
FileName,
|
|
LibName : String ;
|
|
BEGIN
|
|
LibName := NIL ;
|
|
FileName := NIL ;
|
|
SymName := InitStringCharStar (KeyToCharStar (GetSymName (sym))) ;
|
|
IF IsDefImp (sym)
|
|
THEN
|
|
IF FindSourceDefFile (SymName, FileName, LibName)
|
|
THEN
|
|
ModuleType := Definition ;
|
|
ChildDep := MakeSaveTempsFileNameExt (CreateFileStem (SymName, LibName), InitString ('.def.d')) ;
|
|
IF OpenSource (AssociateDefinition (PreprocessModule (FileName, FALSE, TRUE,
|
|
ChildDep), sym))
|
|
THEN
|
|
IF NOT P0SyntaxCheck.CompilationUnit ()
|
|
THEN
|
|
WriteFormat0 ('compilation failed') ;
|
|
CloseSource ;
|
|
SymName := KillString (SymName) ;
|
|
FileName := KillString (FileName) ;
|
|
LibName := KillString (LibName) ;
|
|
RETURN FALSE
|
|
END ;
|
|
qprintf2 (' Module %-20s : %s', SymName, FileName) ;
|
|
qprintLibName (LibName) ;
|
|
PutLibName (sym, makekey (string (LibName))) ;
|
|
IF IsDefinitionForC (sym)
|
|
THEN
|
|
qprintf0 (' (for C)')
|
|
END ;
|
|
IF IsDefLink (sym)
|
|
THEN
|
|
qprintf0 (' (linking)')
|
|
END ;
|
|
qprintf0 ('\n') ;
|
|
CloseSource ;
|
|
MergeDeps (DepContent, ChildDep, LibName)
|
|
ELSE
|
|
(* Unrecoverable error. *)
|
|
MetaErrorString1 (Sprintf1 (InitString ('file {%%1EUAF%s} containing module {%%1a} cannot be found {%%1&Ds}'),
|
|
FileName), sym)
|
|
END
|
|
ELSE
|
|
MetaError1 ('the file containing the definition module {%1EMAa} cannot be found {%1&Ds}', sym)
|
|
END ;
|
|
ModuleType := Implementation
|
|
ELSE
|
|
ModuleType := Program
|
|
END ;
|
|
SymName := KillString (SymName) ;
|
|
FileName := KillString (FileName) ;
|
|
LibName := KillString (LibName) ;
|
|
RETURN TRUE
|
|
END Pass0CheckDef ;
|
|
|
|
|
|
(*
|
|
Pass0CheckMod -
|
|
*)
|
|
|
|
PROCEDURE Pass0CheckMod (sym: CARDINAL; PPSource: String) : BOOLEAN ;
|
|
VAR
|
|
Main : CARDINAL ;
|
|
ChildDep,
|
|
SymName,
|
|
FileName,
|
|
LibName : String ;
|
|
BEGIN
|
|
SymName := InitStringCharStar (KeyToCharStar (GetSymName (sym))) ;
|
|
FileName := NIL ;
|
|
LibName := NIL ;
|
|
Main := GetMainModule () ;
|
|
IF (Main = sym) OR NeedToParseImplementation (sym)
|
|
THEN
|
|
(* Only need to read implementation module if hidden types are
|
|
declared or it is the main module. *)
|
|
IF Main = sym
|
|
THEN
|
|
FileName := Dup (PPSource) ;
|
|
LibName := InitStringCharStar (GetM2Prefix ()) ;
|
|
PutLibName (sym, makekey (string (LibName)))
|
|
ELSE
|
|
IF FindSourceModFile (SymName, FileName, LibName)
|
|
THEN
|
|
ChildDep := MakeSaveTempsFileNameExt (CreateFileStem (SymName, LibName), InitString ('.mod.d')) ;
|
|
FileName := PreprocessModule (FileName, FALSE, TRUE, ChildDep) ;
|
|
PutLibName (sym, makekey (string (LibName))) ;
|
|
MergeDeps (DepContent, ChildDep, LibName)
|
|
ELSE
|
|
qprintf1 (' Module %-20s : implementation source file not found\n', SymName)
|
|
END
|
|
END ;
|
|
|
|
IF FileName # NIL
|
|
THEN
|
|
IF OpenSource (AssociateModule (Dup (FileName), sym))
|
|
THEN
|
|
IF NOT P0SyntaxCheck.CompilationUnit ()
|
|
THEN
|
|
WriteFormat0 ('compilation failed') ;
|
|
CloseSource ;
|
|
SymName := KillString (SymName) ;
|
|
FileName := KillString (FileName) ;
|
|
LibName := KillString (LibName) ;
|
|
RETURN FALSE
|
|
END ;
|
|
qprintf2 (' Module %-20s : %s', SymName, FileName) ;
|
|
qprintLibName (LibName) ;
|
|
IF IsModLink (sym)
|
|
THEN
|
|
qprintf0 (' (linking)')
|
|
END ;
|
|
qprintf0 ('\n') ;
|
|
CloseSource
|
|
ELSE
|
|
(* It is legitimate to implement a module in C (and pretend it was a M2
|
|
implementation) providing that it is not the main program module and the
|
|
definition module does not declare a hidden type when -fextended-opaque
|
|
is used. *)
|
|
IF (NOT WholeProgram) OR (sym = Main) OR IsHiddenTypeDeclared (sym)
|
|
THEN
|
|
(* Unrecoverable error. *)
|
|
MetaErrorString1 (Sprintf1 (InitString ('file {%%1EUAF%s} containing module {%%1a} cannot be found {%%1&Ds}'),
|
|
FileName), sym)
|
|
END
|
|
END
|
|
END
|
|
ELSIF GenModuleList
|
|
THEN
|
|
IF IsDefImp (sym) AND (NOT IsDefinitionForC (sym))
|
|
THEN
|
|
(* The implementation module is only useful if -fgen-module-list= is
|
|
used (to gather all dependencies). Note that we do not insist
|
|
upon finding the implementation module. *)
|
|
LibName := NIL ;
|
|
IF FindSourceModFile (SymName, FileName, LibName)
|
|
THEN
|
|
PutLibName (sym, makekey (string (LibName))) ;
|
|
qprintf2 (' Module %-20s : %s' , SymName, FileName) ;
|
|
qprintLibName (LibName) ;
|
|
qprintf0 (' (linking)\n') ;
|
|
ChildDep := MakeSaveTempsFileNameExt (CreateFileStem (SymName, LibName), InitString ('.mod.d')) ;
|
|
IF OpenSource (AssociateModule (PreprocessModule (FileName, FALSE, TRUE, ChildDep), sym))
|
|
THEN
|
|
PutModLink (sym, TRUE) ; (* This source is only used to determine link time info. *)
|
|
IF NOT P0SyntaxCheck.CompilationUnit ()
|
|
THEN
|
|
WriteFormat0 ('compilation failed') ;
|
|
CloseSource ;
|
|
SymName := KillString (SymName) ;
|
|
FileName := KillString (FileName) ;
|
|
LibName := KillString (LibName) ;
|
|
RETURN FALSE
|
|
END ;
|
|
CloseSource ;
|
|
MergeDeps (DepContent, ChildDep, LibName)
|
|
END
|
|
END
|
|
END
|
|
END ;
|
|
SymName := KillString (SymName) ;
|
|
FileName := KillString (FileName) ;
|
|
LibName := KillString (LibName) ;
|
|
RETURN TRUE
|
|
END Pass0CheckMod ;
|
|
|
|
|
|
(*
|
|
DoPass0 -
|
|
*)
|
|
|
|
PROCEDURE DoPass0 (filename: String) ;
|
|
VAR
|
|
sym : CARDINAL ;
|
|
i : CARDINAL ;
|
|
PPSource : String ;
|
|
BEGIN
|
|
P0Init ;
|
|
SetPassToPass0 ;
|
|
(* Maybe preprocess the main file. *)
|
|
DepOutput := CreateDepFilename (filename) ;
|
|
PPSource := PreprocessModule (filename, TRUE, FALSE, DepOutput) ;
|
|
DepContent := ReadDepContents (filename, DepOutput) ;
|
|
PeepInto (PPSource) ;
|
|
i := 1 ;
|
|
sym := GetModuleNo (i) ;
|
|
qprintf1 ('Compiling: %s\n', PPSource) ;
|
|
IF Debugging
|
|
THEN
|
|
DumpPathName ('DoPass0')
|
|
END ;
|
|
IF Verbose
|
|
THEN
|
|
fprintf1 (StdOut, 'Compiling: %s\n', PPSource)
|
|
END ;
|
|
qprintf0 ('Pass 0: lexical analysis, parsing, modules and associated filenames\n') ;
|
|
WHILE sym # NulSym DO
|
|
IF NOT Pass0CheckDef (sym)
|
|
THEN
|
|
RETURN
|
|
END ;
|
|
IF NOT Pass0CheckMod (sym, PPSource)
|
|
THEN
|
|
RETURN
|
|
END ;
|
|
INC (i) ;
|
|
sym := GetModuleNo (i)
|
|
END ;
|
|
SetPassToNoPass
|
|
END DoPass0 ;
|
|
|
|
|
|
(*
|
|
DoPass1 - parses the sources of all modules necessary to compile
|
|
the required module, Main.
|
|
*)
|
|
|
|
PROCEDURE DoPass1 ;
|
|
VAR
|
|
name : Name ;
|
|
Sym : CARDINAL ;
|
|
i : CARDINAL ;
|
|
FileName: String ;
|
|
BEGIN
|
|
P1Init ;
|
|
SetPassToPass1 ;
|
|
i := 1 ;
|
|
Sym := GetModuleNo(i) ;
|
|
WHILE Sym#NulSym DO
|
|
FileName := GetDefinitionModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF Debugging
|
|
THEN
|
|
name := GetSymName(Sym) ;
|
|
qprintf1(' Module %a\n', name)
|
|
END ;
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
ModuleType := Definition ;
|
|
IF NOT P1Build.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END ;
|
|
ModuleType := Implementation
|
|
ELSE
|
|
ModuleType := Program
|
|
END ;
|
|
FileName := GetModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF Debugging
|
|
THEN
|
|
name := GetSymName(Sym) ;
|
|
qprintf1(' Module %a\n', name)
|
|
END ;
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
IF NOT P1Build.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END
|
|
END ;
|
|
INC(i) ;
|
|
Sym := GetModuleNo(i)
|
|
END ;
|
|
SetPassToNoPass
|
|
END DoPass1 ;
|
|
|
|
|
|
(*
|
|
DoPass2 - parses the sources of all modules necessary to compile
|
|
the required module, Main.
|
|
*)
|
|
|
|
PROCEDURE DoPass2 ;
|
|
VAR
|
|
name : Name ;
|
|
Sym : CARDINAL ;
|
|
i : CARDINAL ;
|
|
FileName: String ;
|
|
BEGIN
|
|
SetPassToPass2 ;
|
|
i := 1 ;
|
|
Sym := GetModuleNo(i) ;
|
|
WHILE Sym#NulSym DO
|
|
FileName := GetDefinitionModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF Debugging
|
|
THEN
|
|
name := GetSymName(Sym) ;
|
|
qprintf1(' Module %a\n', name)
|
|
END ;
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
ModuleType := Definition ;
|
|
IF NOT P2Build.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END ;
|
|
ModuleType := Implementation
|
|
ELSE
|
|
ModuleType := Program
|
|
END ;
|
|
FileName := GetModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF Debugging
|
|
THEN
|
|
name := GetSymName(Sym) ;
|
|
qprintf1(' Module %a\n', name)
|
|
END ;
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
IF NOT P2Build.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END
|
|
END ;
|
|
INC(i) ;
|
|
Sym := GetModuleNo(i)
|
|
END ;
|
|
SetPassToNoPass
|
|
END DoPass2 ;
|
|
|
|
|
|
(*
|
|
DoPassC - parses the sources of all modules necessary to compile
|
|
the required module, Main.
|
|
*)
|
|
|
|
PROCEDURE DoPassC ;
|
|
VAR
|
|
name : Name ;
|
|
Sym : CARDINAL ;
|
|
i : CARDINAL ;
|
|
FileName: String ;
|
|
BEGIN
|
|
SetPassToPassC ;
|
|
i := 1 ;
|
|
Sym := GetModuleNo(i) ;
|
|
WHILE Sym#NulSym DO
|
|
FileName := GetDefinitionModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF Debugging
|
|
THEN
|
|
name := GetSymName(Sym) ;
|
|
qprintf1(' Module %a\n', name)
|
|
END ;
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
ModuleType := Definition ;
|
|
IF NOT PCBuild.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END ;
|
|
ModuleType := Implementation
|
|
ELSE
|
|
ModuleType := Program
|
|
END ;
|
|
FileName := GetModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF Debugging
|
|
THEN
|
|
name := GetSymName(Sym) ;
|
|
qprintf1(' Module %a\n', name)
|
|
END ;
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
IF NOT PCBuild.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END
|
|
END ;
|
|
INC(i) ;
|
|
Sym := GetModuleNo(i)
|
|
END ;
|
|
PCSymBuild.ResolveConstTypes ;
|
|
ResolveConstructorTypes ;
|
|
SanityCheckConstants ;
|
|
SetPassToNoPass
|
|
END DoPassC ;
|
|
|
|
|
|
(*
|
|
DoPass3 - parses the sources of all modules necessary to compile
|
|
the required module, Main.
|
|
*)
|
|
|
|
PROCEDURE DoPass3 ;
|
|
VAR
|
|
Main,
|
|
Sym : CARDINAL ;
|
|
i : CARDINAL ;
|
|
FileName: String ;
|
|
BEGIN
|
|
SetPassToPass3 ;
|
|
Main := GetMainModule() ;
|
|
i := 1 ;
|
|
Sym := GetModuleNo(i) ;
|
|
WHILE Sym#NulSym DO
|
|
FileName := GetDefinitionModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
ModuleType := Definition ;
|
|
IF NOT P3Build.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END ;
|
|
ModuleType := Implementation
|
|
ELSE
|
|
ModuleType := Program
|
|
END ;
|
|
FileName := GetModuleFile(Sym) ;
|
|
IF FileName#NIL
|
|
THEN
|
|
IF OpenSource(FileName)
|
|
THEN
|
|
IF (Main=Sym) OR WholeProgram
|
|
THEN
|
|
IF NOT P3Build.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END
|
|
ELSE
|
|
(*
|
|
not the main module .mod therefore must be implementing
|
|
a hidden type - we dont want to generate any
|
|
StatementSequence quadrupes but we do want to build TYPEs
|
|
and ConstExpressions.
|
|
*)
|
|
SetPassToNoPass ;
|
|
SetPassToPassHidden ;
|
|
IF NOT PHBuild.CompilationUnit()
|
|
THEN
|
|
MetaError0('compilation failed') ;
|
|
CloseSource ;
|
|
RETURN
|
|
END ;
|
|
SetPassToNoPass ;
|
|
SetPassToPass3
|
|
END ;
|
|
CloseSource
|
|
ELSE
|
|
fprintf1(StdErr, 'failed to open %s\n', FileName) ;
|
|
exit(1)
|
|
END
|
|
END ;
|
|
INC(i) ;
|
|
Sym := GetModuleNo(i)
|
|
END ;
|
|
SetPassToNoPass
|
|
END DoPass3 ;
|
|
|
|
|
|
BEGIN
|
|
ModuleType := None ;
|
|
DepContent := NIL ;
|
|
DepOutput := NIL
|
|
END M2Comp.
|