diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/tidydates.py
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/tidydates.py	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,184 @@
+#!/usr/bin/env python3
+
+# utility to tidy dates and detect lack of copyright.
+
+# Copyright (C) 2016-2022 Free Software Foundation, Inc.
+#
+# 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 COPYING.  If not, write to the
+# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+import os, sys
+
+maxLineLength = 60
+
+
+#
+#  visitDir - call func for each file below, dir, matching extension, ext.
+#
+
+def visitDir (dir, ext, func):
+    listOfFiles = os.listdir(dir)
+    listOfFiles.sort()
+    for file in listOfFiles:
+        if os.path.isfile(os.path.join(dir, file)):
+            l = len(ext)
+            if (len(file)>l) and (file[-l:] == ext):
+                func(os.path.join(dir, file))
+        elif os.path.isdir(os.path.join(dir, file)):
+            visitDir(os.path.join(dir, file), ext, func)
+
+#
+#  isYear - returns True if, year, is legal.
+#
+
+def isYear (year):
+    if len(year)==5:
+        year = year[:-1]
+    for c in year:
+        if not c.isdigit():
+            return False
+    return True
+
+
+#
+#  handleCopyright -
+#
+
+def handleCopyright (outfile, lines, n, leader1, leader2):
+    global maxLineLength
+    i = lines[n]
+    c = i.find('Copyright (C) ')+len('Copyright (C)')
+    outfile.write(i[:c])
+    d = i[c:].split()
+    start = c
+    seenDate = True
+    years = []
+    while seenDate:
+        if d == []:
+            n += 1
+            i = lines[n]
+            d = i[2:].split()
+        else:
+            e = d[0]
+            punctuation = ""
+            if len(d)==1:
+                d = []
+            else:
+                d = d[1:]
+
+            if c>maxLineLength:
+                outfile.write('\n')
+                outfile.write(leader1)
+                outfile.write(leader2)
+                outfile.write(' '*(start-2))
+                c = start
+
+            if isYear(e):
+                if (e[-1]=='.') or (e[-1]==','):
+                    punctuation = e[-1]
+                    e = e[:-1]
+                else:
+                    punctuation = ""
+            else:
+                seenDate = False
+            if seenDate:
+                if not (e in years):
+                    c += len(e) + len(punctuation)
+                    outfile.write(' ')
+                    outfile.write(e)
+                    outfile.write(punctuation)
+                    years += [e]
+            else:
+                if start < c:
+                    outfile.write('\n')
+                    outfile.write(leader1)
+                    outfile.write(leader2)
+                    outfile.write(' '*(start-2))
+
+                outfile.write(' ')
+                outfile.write(e)
+                outfile.write(punctuation)
+                for w in d:
+                    outfile.write(' ')
+                    outfile.write(w)
+
+    outfile.write('\n')
+    return outfile, n+1
+
+#
+#  handleHeader - reads in the header of a file and inserts
+#                 a line break around the Copyright dates.
+#
+
+def handleHeader (file, leader1, leader2):
+    print("------------------------------")
+    l = open(file, 'r').readlines()
+    if len(l)>20:
+        outfile = open('tmptidy', 'w')
+        n = 0
+        for i in l:
+            if i.find('Copyright (C)')>=0:
+                outfile, n = handleCopyright(outfile, l, n, leader1, leader2)
+                outfile.writelines(l[n:])
+                outfile.close()
+                print("-> mv tmptidy", file)
+                command = "mv tmptidy %s" % file
+                os.system(command)
+                return
+            else:
+                outfile.write(l[n])
+                n += 1
+        outfile.close()
+        sys.stdout.write("%s:1:1 needs a Copyright notice..\n" % file)
+
+
+#
+#  bashTidy - tidy up dates using '#' comment
+#
+
+def bashTidy (file):
+    handleHeader(file, '#', ' ')
+
+#
+#  cTidy - tidy up dates using '/* */' comments
+#
+
+def cTidy (file):
+    handleHeader(file, ' ', '*')
+
+#
+#  m2Tidy - tidy up dates using '(* *)' comments
+#
+
+def m2Tidy (file):
+    handleHeader(file, ' ', ' ')
+
+#
+#  main - for each file extension call the appropriate tidy
+#         routine.
+#
+
+def main ():
+    visitDir('.', '.in', bashTidy)
+    visitDir('.', '.py', bashTidy)
+    visitDir('.', '.c', cTidy)
+    visitDir('.', '.h', cTidy)
+    visitDir('.', '.def', m2Tidy)
+    visitDir('.', '.mod', m2Tidy)
+
+
+main ()
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/boilerplate.py
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/boilerplate.py	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,599 @@
+#!/usr/bin/env python3
+# 
+# boilerplate.py utility to rewrite the boilerplate with new dates.
+# 
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
+# Contributed by Gaius Mulley <gaius@glam.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/>.
+#
+import sys
+import os
+import glob
+import sys, getopt, string
+import datetime
+
+forceGPL3x, forceGPL3 = False, False
+doModify, verbose = True, False,
+multiFilemode, updateAll, forceCheck = False, False, False
+
+summaryGiven, contributedBy, outputName = "", "", "-"
+errorCount = 0
+startDir = "."
+seenFiles = []
+
+
+#
+#  printf - keeps C programmers happy :-)
+#
+
+def printf (fmt, *args):
+    print(str (fmt) % args, end=' ')
+
+#
+#  error - issue an error message.
+#
+
+def error (fmt, *args):
+    global errorCount
+
+    print(str (fmt) % args, end=' ')
+    errorCount += 1
+
+
+def haltOnError ():
+    if errorCount > 0:
+        os.sys.exit (1)
+
+
+def basename (f):
+    b = f.split ("/")
+    return b[-1]
+
+
+#
+#  analyseComment -
+#
+
+def analyseComment (text, f):
+    start_date, end_date, contribution, summary, lic = None, None, None, None, None
+    if text.find ("Copyright ISO/IEC") > 0:
+        lic = "BSISO"
+        now = datetime.datetime.now ()
+        for d in range (1984, now.year+1):
+            if text.find (str (d)) > 0:
+                if start_date == None:
+                    start_date = str (d)
+                end_date = str (d)
+        return start_date, end_date, "", "", lic
+    elif text.find ("Copyright (C)") > 0:
+        if text.find ("GNU General Public License") > 0:
+            lic = "GPL"
+        elif text.find ("GNU Lesser General") > 0:
+            lic = "LGPL"
+        if text.find ("version 2.1") > 0:
+            lic += "v2.1"
+        elif text.find ("version 2") > 0:
+            lic += "v2"
+        elif text.find ("version 3") > 0:
+            lic += "v3"
+        if text.find ("GCC Runtime Library Exception") > 0:
+            lic += "x"
+        now = datetime.datetime.now ()
+        for d in range (1984, now.year+1):
+            if text.find (str (d)) > 0:
+                if start_date == None:
+                    start_date = str (d)
+                end_date = str (d)
+        if text.find ("ontributed by") > 0:
+            i = text.find ("ontributed by")
+            i += len ("ontributed by")
+            j = text.index (". ", i)
+            contribution = text[i:j]
+    if text.find (basename (f)) > 0:
+        i = text.find (basename (f))
+        j = text.find (". ", i)
+        if j < 0:
+            error ('summary of the file does not finish with a "."')
+            summary = text[i:]
+        else:
+            summary = text[i:j]
+    return start_date, end_date, contribution, summary, lic
+
+
+#
+#  analyseHeader -
+#
+
+def analyseHeader (f, start, end):
+    text = ""
+    if end == None:
+        for count, l in enumerate (open (f, "r").readlines ()):
+            parts = l.split (start)
+            if len (parts) > 1:
+                line = start.join (parts[1:])
+                line = line.rstrip ()
+                line = line.lstrip ()
+                text += " "
+                text += line
+            elif (l.rstrip () != "") and (len (parts[0]) > 0):
+                return analyseComment (text, f), count
+    else:
+        inComment = False
+        for count, l in enumerate (open (f, "r").readlines ()):
+            while l != "":
+                l = l.strip ()
+                l = l.rstrip ()
+                if inComment:
+                    text += " "
+                    pos = l.find (end)
+                    if pos >= 0:
+                        text += l[:pos]
+                        l = l[pos:]
+                        inComment = False
+                    else:
+                        text += l
+                        l = ""
+                else:
+                    pos = l.find (start)
+                    if (pos >= 0) and (len (l) > len (start)):
+                        before = l[:pos]
+                        before = before.rstrip ()
+                        before = before.lstrip ()
+                        if before != "":
+                            return analyseComment (text, f), count
+                        l = l[pos + len (start):]
+                        inComment = True
+                    elif (l != "") and (l == end):
+                        l = ""
+                    else:
+                        return analyseComment (text, f), count
+    return [None, None, None, None, None], 0
+
+
+#
+#  addStop - add a full stop to a sentance.
+#
+
+def addStop (sentence):
+    if sentence is None:
+        return None
+    sentence = sentence.rstrip ()
+    if (len (sentence) > 0) and (sentence[-1] != "."):
+        return sentence + "."
+    return sentence
+
+
+GPLv3 = """
+%s
+
+Copyright (C) %s Free Software Foundation, Inc.
+Contributed by %s
+
+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/>.
+"""
+
+GPLv3x = """
+%s
+
+Copyright (C) %s Free Software Foundation, Inc.
+Contributed by %s
+
+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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.
+"""
+
+LGPLv3 = """
+%s
+
+Copyright (C) %s Free Software Foundation, Inc.
+Contributed by %s
+
+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 Lesser General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with GNU Modula-2.  If not, see <https://www.gnu.org/licenses/>.
+"""
+
+BSISO = """
+Library module defined by the International Standard
+   Information technology - programming languages
+   BS ISO/IEC 10514-1:1996E Part 1: Modula-2, Base Language.
+
+   Copyright ISO/IEC (International Organization for Standardization
+   and International Electrotechnical Commission) %s.
+
+   It may be freely copied for the purpose of implementation (see page
+   707 of the Information technology - Programming languages Part 1:
+   Modula-2, Base Language.  BS ISO/IEC 10514-1:1996).
+"""
+
+templates = { "GPLv3":GPLv3,
+              "GPLv3x":GPLv3x,
+              "LGPLv3":LGPLv3,
+              "LGPLv2.1":LGPLv3,
+              "BSISO":BSISO }
+
+
+def writeTemplate (fo, magic, start, end, dates, contribution, summary, lic):
+    if lic in templates:
+        if lic == "BSISO":
+            # non gpl but freely distributed for the implementation of a compiler
+            text = templates[lic] % (dates)
+            text = text.rstrip ()
+        else:
+            summary = summary.lstrip ()
+            contribution = contribution.lstrip ()
+            summary = addStop (summary)
+            contribution = addStop (contribution)
+            if magic != None:
+                fo.write (magic)
+                fo.write ("\n")
+            text = templates[lic] % (summary, dates, contribution)
+            text = text.rstrip ()
+        if end == None:
+            text = text.split ("\n")
+            for line in text:
+                fo.write (start)
+                fo.write (" ")
+                fo.write (line)
+                fo.write ("\n")
+        else:
+            text = text.lstrip ()
+            fo.write (start)
+            fo.write (" ")
+            fo.write (text)
+            fo.write ("  ")
+            fo.write (end)
+            fo.write ("\n")
+        # add a blank comment line for a script for eye candy.
+        if start == "#" and end == None:
+            fo.write (start)
+            fo.write ("\n")
+    else:
+        error ("no template found for: %s\n", lic)
+        os.sys.exit (1)
+    return fo
+
+
+def writeBoilerPlate (fo, magic, start, end, start_date, end_date, contribution, summary, gpl):
+    if start_date == end_date:
+        dates = start_date
+    else:
+        dates = "%s-%s" % (start_date, end_date)
+    return writeTemplate (fo, magic, start, end, dates, contribution, summary, gpl)
+
+
+def rewriteFile (f, magic, start, end, start_date, end_date, contribution, summary, gpl, lines):
+    l = open (f, "r").readlines ()[lines:]
+    text = "".join (l)
+    if outputName == "-":
+        fo = sys.stdout
+    else:
+        fo = open (f, "w")
+    fo = writeBoilerPlate (fo, magic, start, end, start_date, end_date, contribution, summary, gpl)
+    fo.write (text)
+    fo.flush ()
+    if outputName != "-":
+        fo.close ()
+
+
+#
+#  handleHeader - keep reading lines of file, f, looking for start, end
+#                 sequences and comments inside.  The comments are checked
+#                 for:  date, contribution, summary
+#
+
+def handleHeader (f, magic, start, end):
+    global date, contribution, summary, doModify, forceCheck, errorCount
+
+    errorCount = 0
+    [start_date, end_date, contribution, summary, lic], lines =  analyseHeader (f, start, end)
+    if lic == None:
+        error ("%s:1:no GPL found at the top of the file\n", f)
+    else:
+        if verbose:
+            printf ("copyright: %s\n", lic)
+            if (start_date != None) and (end_date != None):
+                if start_date == end_date:
+                    printf ("dates = %s\n", start_date)
+                else:
+                    printf ("dates = %s-%s\n", start_date, end_date)
+            if summary != None:
+                printf ("summary: %s\n", summary)
+            if contribution != None:
+                printf ("contribution: %s\n", contribution)
+        if start_date == None:
+            error ("%s:1:no date found in the GPL at the top of the file\n", f)
+        if contribution == None:
+            if contributedBy == "":
+                error ("%s:1:no contribution found in the GPL at the top of the file\n", f)
+            else:
+                contribution = contributedBy
+        if summary == None:
+            if summaryGiven == "":
+                error ("%s:1:no single line summary found in the GPL at the top of the file\n", f)
+            else:
+                summary = summaryGiven
+    if errorCount == 0:
+        now = datetime.datetime.now ()
+        if doModify:
+            if lic == "BSISO":
+                # don't change the BS ISO license!
+                pass
+            elif forceGPL3x:
+                lic = "GPLv3x"
+            elif forceGPL3:
+                lic = "GPLv3"
+            rewriteFile (f, magic, start, end, start_date, str (now.year), contribution, summary, lic, lines)
+        elif forceCheck:
+            print(f, "suppressing change as requested", start_date, end_date, lic)
+    else:
+        printf ("too many errors, no modifications will occur\n")
+
+
+#
+#  bashTidy - tidy up dates using '#' comment
+#
+
+def bashTidy (f):
+    handleHeader (f, "#!/bin/bash", "#", None)
+
+
+#
+#  pythonTidy - tidy up dates using '#' comment
+#
+
+def pythonTidy (f):
+    handleHeader (f, "#!/usr/bin/env python3", '#', None)
+
+
+#
+#  bnfTidy - tidy up dates using '--' comment
+#
+
+def bnfTidy (f):
+    handleHeader (f, None, '--', None)
+
+
+#
+#  cTidy - tidy up dates using '/* */' comments
+#
+
+def cTidy (f):
+    handleHeader (f, None, '/*', '*/')
+
+#
+#  m2Tidy - tidy up dates using '(* *)' comments
+#
+
+def m2Tidy (f):
+    handleHeader (f, None, '(*', '*)')
+
+#
+#  inTidy - tidy up dates using '#' as a comment and check the first line for magic number.
+#
+
+def inTidy (f):
+    first = open (f, "r").readlines ()[0]
+    if (len (first) > 0) and (first[:2] == "#!"):
+        # magic number found, use this
+        handleHeader (f, first, "#", None)
+    else:
+        handleHeader (f, None, "#", None)
+
+
+#
+#  doVisit -
+#
+
+def doVisit (args, dirname, names):
+    global outputName
+    func, extension = args
+    for f in names:
+        if len (f) > len (extension) and f[-len (extension):] == extension:
+            # print os.path.join (dirname, f)
+            outputName = f
+            func (os.path.join (dirname, f))
+
+
+#
+#  visitDir - visit
+#
+
+def visitDir (startDir, extension, func):
+    global outputName, seenFiles
+    # os.walk (startDir, doVisit, [func, extension])
+    for dirName, subdirList, fileList in os.walk(startDir):
+        for fname in fileList:
+            if (len (fname) > len (extension)) and (fname[-len(extension):] == extension):
+                fullpath = os.path.join (dirName, fname)
+                outputName = fullpath
+                # printf ("outputName = %s\n", outputName)
+                if not (fullpath in seenFiles):
+                    seenFiles += [fullpath]
+                    func (fullpath)
+            # Remove the first entry in the list of sub-directories
+            # if there are any sub-directories present
+        if len(subdirList) > 0:
+            del subdirList[0]
+
+#
+#  findFiles - for each file extension call the appropriate tidy
+#              routine.
+#
+
+def findFiles ():
+    visitDir (startDir, '.h.in', cTidy)
+    visitDir (startDir, '.in', inTidy)
+    visitDir (startDir, '.sh', inTidy)
+    visitDir (startDir, '.py', pythonTidy)
+    visitDir (startDir, '.c', cTidy)
+    visitDir (startDir, '.h', cTidy)
+    visitDir (startDir, '.cc', cTidy)
+    visitDir (startDir, '.def', m2Tidy)
+    visitDir (startDir, '.mod', m2Tidy)
+    visitDir (startDir, '.bnf', bnfTidy)
+
+
+#
+#  usage - output very brief usage instructions.
+#
+
+def usage (code = 0):
+    print("boilerplate [-c contributionstring] [ -s summarystring ] [-d] [-v] [-g] [-x] [-o outputfile] inputfile.c")
+    print("  -o outputfile   (this must be before the final inputfile on the command line).")
+    print("  -c              a string which will be used as the contribution line.")
+    print("  -s              a string which will be used as the summary line.")
+    print("  -f              force a check to insist that the contribution, summary and GPL exists.")
+    print("  -g              change to GPLv3.")
+    print("  -x              change to GPLv3 with GCC runtime extension.")
+    print("  -r directory    recusively scan directory for known file extensions (.def, .mod, .c, .h, .py, .in, .sh).")
+    print("  -u              update all dates.")
+    print("  -v              verbose.")
+    print("  -N              do not modify any file")
+    os.sys.exit (code)
+
+
+#
+#  handleArguments - check the legal arguments.
+#
+
+def handleArguments ():
+    global multiFilemode, contributedBy, updateAll, forceCheck, outputName, verbose, startDir, doModify, forceGPL3, forceGPL3x, summaryGiven
+    try:
+        optlist, l = getopt.getopt (sys.argv[1:],':c:dfgho:r:s:uvxN')
+    except getopt.GetoptError:
+        usage (1)
+    for opt in optlist:
+        if opt[0] == '-c':
+            contributedBy = opt[1]
+        if opt[0] == '-s':
+            summaryGiven = opt[1]
+        if opt[0] == '-d':
+            debugging = True
+        if opt[0] == '-f':
+            forceCheck = True
+        if opt[0] == '-g':
+            forceGPL3 = True
+        if opt[0] == '-x':
+            forceGPL3x = True
+        if opt[0] == '-h':
+            usage ()
+        if opt[0] == '-r':
+            multiFilemode = True
+            startDir = opt[1]
+        if opt[0] == '-o':
+            outputName = opt[1]
+        if opt[0] == '-u':
+            updateAll = True
+        if opt[0] == '-v':
+            verbose = True
+        if opt[0] == '-N':
+            doModify = False
+    if l == []:
+        return None
+    return l[0]
+
+
+#
+#  hasExt - return True if, name, ends with, ext.
+#
+
+def hasExt (name, ext):
+    if len (name) > len (ext):
+        return name[-len (ext):] == ext
+    return False
+
+
+#
+#  singleFile - scan the single file for a GPL boilerplate which
+#               has a GPL, contribution field and a summary heading.
+#
+
+def singleFile (i):
+    if hasExt (i, ".def") or hasExt (i, ".mod"):
+        m2Tidy (i)
+    elif hasExt (i, ".h") or hasExt (i, ".c") or hasExt (i, ".cc"):
+        cTidy (i)
+    elif hasExt (i, ".in"):
+        inTidy (i)
+    elif hasExt (i, ".sh"):
+        inTidy (i)  # uses magic number for actual sh/bash
+    elif hasExt (i, ".py"):
+        pythonTidy (i)
+
+
+#
+#  main - handleArguments and then find source files.
+#
+
+def main ():
+    i = handleArguments ()
+    if multiFilemode:
+        findFiles ()
+    elif i == None:
+        print("an input file must be specified on the command line")
+        usage (1)
+    else:
+        singleFile (i)
+    haltOnError ()
+
+
+main ()
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/buildpg
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/buildpg	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,289 @@
+#!/bin/sh
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+# 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 COPYING.  If not, write to the
+# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+# builds the pg.bnf from ppg.mod
+# usage buildpg ppg.mod destination [-e]
+#    -e   build without error recovery
+#
+PPGSRC=$1
+PPGDST=$2
+
+includeNonErrorChecking () {
+   sed -e "1,/StartNonErrorChecking/d" < $PPGSRC |\
+   sed -e "1,/EndNonErrorChecking/!d"
+}
+
+includeErrorChecking () {
+   sed -e "1,/StartErrorChecking/d" < $PPGSRC |\
+   sed -e "1,/EndErrorChecking/!d"
+}
+
+
+echo "% module" $PPGDST "begin"
+sed -e "1,/% declaration/!d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g"
+
+echo "% declaration" $PPGDST "begin"
+
+sed -e "1,/% declaration/d" < $PPGSRC | sed -e "1,/% rules/!d" | sed -e "s/ppg/${PPGDST}/g"
+
+if [ "$3" = "-e" ] ; then
+   includeNonErrorChecking
+   echo "% module" $PPGDST "end"
+   sed -e "1,/% module pg end/d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g"
+else
+   includeErrorChecking
+   echo "% module" $PPGDST "end"
+   sed -e "1,/% module pg end/d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g" |\
+   sed -e "s/WasNoError := Main() ;/Main({eoftok}) ;/"
+fi
+
+echo "% rules"
+
+cat << EOFEOF  | sed -e "s/ppg/${PPGDST}/g"
+error       'WarnError' 'WarnString'
+tokenfunc   'GetCurrentTokenType()'
+
+token   'identifier'  identtok      -- internal token
+token   'literal'     literaltok
+token   '%'           codetok
+token   ':='          lbecomestok
+token   '=:'          rbecomestok
+token   '|'           bartok
+token   '['           lsparatok
+token   ']'           rsparatok
+token   '{'           lcparatok   -- left  curly para
+token   '}'           rcparatok   -- right curly para
+token   '('           lparatok
+token   ')'           rparatok
+token   "error"       errortok
+token   "tokenfunc"   tfunctok
+token   "symfunc"     symfunctok
+token   '"'           dquotetok
+token   "'"           squotetok
+token   "module"      moduletok
+token   "begin"       begintok
+token   "rules"       rulestok
+token   "end"         endtok
+token   '<'           lesstok
+token   '>'           gretok
+token   "token"       tokentok
+token   "special"     specialtok
+token   "first"       firsttok
+token   "follow"      followtok
+token   "BNF"         BNFtok
+token   "FNB"         FNBtok
+token   "declaration" declarationtok
+token   "epsilon"     epsilontok
+token   ''            eoftok      -- internal token
+
+special Ident          first { < identtok > }   follow { }
+special Modula2Code    first { }                follow { '%' }
+special StartModName   first { < identtok > }   follow { }
+special EndModName     first { < identtok > }   follow { }
+special DoDeclaration  first { < identtok > }   follow { }
+special CollectLiteral first { < literaltok > } follow { }
+special CollectTok     first { < identtok > }   follow { }
+special DefineToken    first { < identtok > }   follow { }
+
+BNF
+
+Rules      := "%" "rules" { Defs } ExtBNF =:
+
+Special    := Ident
+              % VAR p: ProductionDesc ; %
+              %     p                           := NewProduction() ;
+                    p^.statement                := NewStatement() ;
+                    p^.statement^.followinfo^.calcfollow := TRUE ;
+                    p^.statement^.followinfo^.epsilon    := false ;
+                    p^.statement^.followinfo^.reachend   := false ;
+                    p^.statement^.ident         := CurrentIdent ;
+                    p^.statement^.expr          := NIL ;
+                    p^.firstsolved              := TRUE ;
+                    p^.followinfo^.calcfollow   := TRUE ;
+                    p^.followinfo^.epsilon      := false ;
+                    p^.followinfo^.reachend     := false %
+              First Follow [ "epsilon" % p^.statement^.followinfo^.epsilon  := true ;  (* these are not used - but they are displayed when debugging *)
+                                         p^.statement^.followinfo^.reachend := true ;
+                                         p^.followinfo^.epsilon  := true ;
+                                         p^.followinfo^.reachend := true
+                                       % ]
+              [ Literal % p^.description := LastLiteral % ]
+              =:
+
+Factor     := "%" Modula2Code "%" |
+              Ident % WITH CurrentFactor^ DO
+                         type  := id ;
+                         ident := CurrentIdent
+                      END ; % |
+              Literal % WITH CurrentFactor^ DO
+                           type   := lit ;
+                           string := LastLiteral ;
+                           IF GetSymKey(Aliases, LastLiteral)=NulName
+                           THEN
+                              WarnError1('no token defined for literal %s', LastLiteral)
+                           END
+                        END ; % |
+              "{" % WITH CurrentFactor^ DO
+                       type := mult ;
+                       expr := NewExpression() ;
+                       CurrentExpression := expr ;
+                    END ; %
+                    Expression "}" |
+              "[" % WITH CurrentFactor^ DO
+                       type := opt ;
+                       expr := NewExpression() ;
+                       CurrentExpression := expr ;
+                    END ; %
+                    Expression "]" |
+              "(" % WITH CurrentFactor^ DO
+                       type := sub ;
+                       expr := NewExpression() ;
+                       CurrentExpression := expr ;
+                    END ; %
+                    Expression ")" =:
+
+Statement  := % VAR i: IdentDesc ; %
+              Ident
+              % VAR p: ProductionDesc ; %
+              % p := FindDefinition(CurrentIdent^.name) ;
+                IF p=NIL
+                THEN
+                   p := NewProduction()
+                ELSE
+                   IF NOT ((p^.statement=NIL) OR (p^.statement^.expr=NIL))
+                   THEN
+                      WarnError1('already declared rule %s', CurrentIdent^.name)
+                   END
+                END ;
+                i := CurrentIdent ; %
+              ":="
+              % VAR e: ExpressionDesc ; %
+              % e := NewExpression() ;
+                CurrentExpression := e ; %
+              % VAR s: StatementDesc ; %
+              % s := NewStatement() ;
+                WITH s^ DO
+                   ident := i ;
+                   expr  := e
+                END ; %
+              Expression
+              % p^.statement := s ; %
+              "=:" =:
+
+Defs       := "special" Special | "token" Token | "error" ErrorProcedures |
+              "tokenfunc" TokenProcedure | "symfunc" SymProcedure =:
+ExtBNF     := "BNF" { Production } "FNB" =:
+Main       := Header Decls Footer Rules =:
+Header     := "%" "module" StartModName =:
+Decls      := "%" "declaration" DoDeclaration =:
+Footer     := "%" "module" EndModName =:
+
+First      := "first"  "{" { LitOrTokenOrIdent
+                             % WITH CurrentSetDesc^ DO
+                                  next := TailProduction^.first ;
+                               END ;
+                               TailProduction^.first := CurrentSetDesc
+                             %
+                           } "}" =:
+Follow     := "follow" "{" { LitOrTokenOrIdent
+                             % WITH CurrentSetDesc^ DO
+                                  next := TailProduction^.followinfo^.follow ;
+                               END ;
+                               TailProduction^.followinfo^.follow := CurrentSetDesc
+                             %
+                           } "}" =:
+LitOrTokenOrIdent := Literal % CurrentSetDesc := NewSetDesc() ;
+                               WITH CurrentSetDesc^ DO
+                                  type   := litel ;
+                                  string := LastLiteral ;
+                               END ;
+                              % |
+                     '<' CollectTok '>' |
+                     Ident % CurrentSetDesc := NewSetDesc() ;
+                             WITH CurrentSetDesc^ DO
+                                type   := idel ;
+                                ident  := CurrentIdent ;
+                             END ;
+                           % =:
+
+Literal    := '"' CollectLiteral '"' |
+              "'" CollectLiteral "'" =:
+
+CollectTok := % CurrentSetDesc := NewSetDesc() ;
+                WITH CurrentSetDesc^ DO
+                   type   := tokel ;
+                   string := GetCurrentToken() ;
+                END ;
+                IF NOT ContainsSymKey(Values, GetCurrentToken())
+                THEN
+                   AddEntry(Values, GetCurrentToken(), LargestValue) ;
+                   AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
+                   AddEntry(Aliases, GetCurrentToken(), GetCurrentToken()) ;
+                   AddEntry(ReverseAliases, GetCurrentToken(), GetCurrentToken()) ;
+                   INC(LargestValue)
+                END ;
+                AdvanceToken() ; % =:
+
+CollectLiteral := % LastLiteral := GetCurrentToken() ;
+                    AdvanceToken ; % =:
+
+DefineToken := %  AddEntry(Aliases, LastLiteral, GetCurrentToken()) ;
+                  AddEntry(ReverseAliases, GetCurrentToken(), LastLiteral) ;
+                  AddEntry(Values, GetCurrentToken(), LargestValue) ;
+                  AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ;
+                  INC(LargestValue) ;
+                  AdvanceToken ; % =:
+
+Token      := Literal DefineToken =:
+
+ErrorProcedures  := Literal % ErrorProcArray := LastLiteral %
+                    Literal % ErrorProcString := LastLiteral % =:
+TokenProcedure := Literal % TokenTypeProc := LastLiteral % =:
+SymProcedure   := Literal % SymIsProc := LastLiteral % =:
+
+Production := Statement =:
+Expression := % VAR t1, t2: TermDesc ;
+                    e     : ExpressionDesc ; %
+              % e := CurrentExpression ;
+                t1 := NewTerm() ;
+                CurrentTerm := t1 ; %
+                Term % e^.term := t1 ; %
+                { "|" % t2 := NewTerm() ;
+                        CurrentTerm := t2 %
+                        Term % t1^.next := t2 ;
+                               t1 := t2 % } =:
+
+Term       := % VAR    t1: TermDesc ; f1, f2: FactorDesc ; %
+              % CurrentFactor := NewFactor() ;
+                f1 := CurrentFactor ;
+                t1 := CurrentTerm ; %
+              Factor % t1^.factor := f1 ;
+                       f2 := NewFactor() ;
+                       CurrentFactor := f2 %
+              { Factor % f1^.next := f2 ;
+                         f1 := f2 ;
+                         f2 := NewFactor() ;
+                         CurrentFactor := f2 ; % }
+           =:
+
+FNB
+
+EOFEOF
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/calcpath
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/calcpath	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# calcpath return a path which is $1/$2/$3 when $2 is relative and $2/$3 if absolute.
+
+# Copyright (C) 2021-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 gm2; see the file COPYING.  If not, write to the Free Software
+# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *)
+
+
+Usage () {
+   echo "Usage: calcpath pathcomponent1 pathcomponent2 subdir"
+   echo -n "  if pathcomponent1 is relative then pathcomponent1/pathcomponet2/subdir is"
+   echo " returned"
+   echo "  otherwise pathcomponet2/subdir is returned"
+   echo "  the path is checked for legality in subdir."
+}
+
+
+if [ $# -eq 3 ]; then
+   if [ "$(echo $2 | cut -b 1)" = "." ] ; then
+       # relative path
+       the_path=$1/$2/$3
+   else
+       the_path=$2/$3
+   fi
+   cd $3
+   if realpath ${the_path} > /dev/null ; then
+       echo ${the_path}
+   else
+       echo "calcpath: error ${the_path} is not a valid path in subdirectory $3" 1>&2
+       exit 1
+   fi
+else
+   Usage
+   exit 1
+fi
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/makeSystem
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/makeSystem	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+# makeSystem creates a target SYSTEM.def using the appropriate dialect template.
+
+# Copyright (C) 2008-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 gm2; see the file COPYING.  If not, write to the Free Software
+# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *)
+
+
+Usage () {
+   echo "Usage: makesystem dialectflag SYSTEM.def SYSTEM.mod librarypath compiler"
+}
+
+if [ $# -lt 6 ] ; then
+   Usage
+   exit 1
+fi
+
+DIALECT=$1
+SYSTEMDEF=$2
+SYSTEMMOD=$3
+LIBRARY=$4
+COMPILER=$5
+OUTPUTFILE=$6
+
+if [ "$COMPILER" = "" ] ; then
+    echo "parameter 5 of makeSystem is incorrect, GM2_FOR_TARGET was unset"
+    exit 1
+fi
+
+if [ "$DIALECT" != "-fiso" -a "$DIALECT" != "-fpim" ] ; then
+   Usage
+   echo "dialect must be -fiso or -fpim"
+   exit 1
+fi
+
+displayExportedTypes () {
+   n=1
+   c=0
+   for i in ${types} ; do
+      if [ $n -eq 1 ] ; then
+          n=0
+          echo -n "                 " >> ${OUTPUTFILE}
+      fi
+      echo -n "$i, " >> ${OUTPUTFILE}
+      if [ $c -eq 4 ] ; then
+          echo " " >> ${OUTPUTFILE}
+          n=1
+          c=0
+      fi
+      c=`expr $c + 1`
+   done
+   echo " " >> ${OUTPUTFILE}
+}
+
+displayBuiltinTypes () {
+   for i in ${types} ; do
+      echo "   $i ; " >> ${OUTPUTFILE}
+   done
+}
+
+displayStart () {
+   sed -e "1,/@SYSTEM_DATATYPES@/!d" < ${SYSTEMDEF} | \
+   sed -e "/@SYSTEM_DATATYPES@/d" >> ${OUTPUTFILE}
+}
+
+displayMiddle () {
+   sed -e "1,/@SYSTEM_DATATYPES@/d" < ${SYSTEMDEF} | \
+   sed -e "1,/@SYSTEM_TYPES@/!d" | \
+   sed -e "/@SYSTEM_TYPES@/d" >> ${OUTPUTFILE}
+}
+
+displayEnd () {
+   sed -e "1,/@SYSTEM_TYPES@/d" < ${SYSTEMDEF} >> ${OUTPUTFILE}
+}
+
+MINIMAL="-fno-scaffold-main -fno-scaffold-dynamic -fno-scaffold-static -fno-m2-plugin"
+
+rm -f ${OUTPUTFILE}
+if ${COMPILER} ${DIALECT} ${LIBRARY} ${MINIMAL} \
+	       -c -fdump-system-exports ${SYSTEMMOD} -o /dev/null 2>&1 > /dev/null ; then
+    types=`${COMPILER} ${DIALECT} ${LIBRARY} ${MINIMAL} -fno-m2-plugin -c -fdump-system-exports ${SYSTEMMOD} -o /dev/null | cut -f5 -d' '`
+    touch ${OUTPUTFILE}
+    displayStart
+    displayExportedTypes
+    displayMiddle
+    displayBuiltinTypes
+    displayEnd
+else
+    ${COMPILER} ${DIALECT} ${LIBRARY} ${MINIMAL} \
+		-c -fdump-system-exports ${SYSTEMMOD} -o /dev/null
+    exit $?
+fi
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/README
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/README	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,3 @@
+This directory contains miscellaneous scripts and programs (mklink.c)
+to allow for bootstrap linking and creating library documentation from
+sources.
\ No newline at end of file
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/mklink.c
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/mklink.c	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,810 @@
+/* mklink.c creates startup code and the link command line.
+
+Copyright (C) 2000-2022 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaius@glam.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/>.  */
+
+
+#include "config.h"
+#include "system.h"
+
+#define MAX_FILE_NAME 8192
+#define MAXSTACK 4096
+#define STDIN 0
+#define STDOUT 1
+#define ENDOFILE ((char)-1)
+#define ERROR(X) \
+  (fprintf (stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) \
+   && (fflush (stderr)))
+#define DEBUG(X) \
+  ((Debug) && (fprintf (stderr, "%s\n", X) && (fflush (stderr))))
+
+#if !defined(TRUE)
+#define TRUE (1 == 1)
+#endif
+
+#if !defined(FALSE)
+#define FALSE (1 == 0)
+#endif
+
+typedef struct functlist
+{
+  char *functname;
+  struct functlist *next;
+} functList;
+
+/* Prototypes.  */
+
+static void ParseFileLinkCommand (void);
+static void ParseFileStartup (void);
+static void ParseFile (char *Name);
+static void ParseComments (void);
+static void CopyUntilEof (void);
+static void CopyUntilEol (void);
+static int IsSym (char *s);
+static int SymIs (char *s);
+static int FindString (char *String);
+static void GetNL (void);
+static char GetChar (void);
+static void ResetBuffer (void);
+static int GetSingleChar (char *ch);
+static int InRange (int Element, unsigned int Min, unsigned int Max);
+static char PutChar (char ch);
+static int IsSpace (char ch);
+static void SkipSpaces (void);
+static void SkipText (void);
+static void SilentSkipSpaces (void);
+static void SilentSkipText (void);
+static void PushBack (char *s);
+static int IsDigit (char ch);
+static void GetName (char *Name);
+static void OpenOutputFile (void);
+static void CloseFile (void);
+static void FindSource (char *Name);
+static void CopyUntilEolInto (char *Buffer);
+static void FindObject (char *Name);
+static int IsExists (char *Name);
+
+/* Global variables.  */
+
+static char *NameOfFile = NULL;
+static const char *NameOfMain = "main";
+static int StackPtr = 0;
+static char Stack[MAXSTACK];
+static int CurrentFile = STDIN;
+static int OutputFile;
+static int LinkCommandLine = FALSE;
+static int ProfilePCommand = FALSE;
+static int ProfilePGCommand = FALSE;
+static int ExitNeeded = TRUE;
+static char *libraries = NULL;
+static char *args = NULL;
+static functList *head = NULL;
+static functList *tail = NULL;
+static int langC = FALSE; /* FALSE = C++, TRUE = C.  */
+
+/* addLibrary - adds libname to the list of libraries to be linked.  */
+
+static void
+addLibrary (char *libname)
+{
+  if (libraries == NULL)
+    libraries = strdup (libname);
+  else
+    {
+      char *old = libraries;
+      char *newlib
+          = (char *)malloc (strlen (libname) + strlen (libraries) + 1 + 1);
+      strcpy (newlib, libraries);
+      strcat (newlib, " ");
+      strcat (newlib, libname);
+      libraries = newlib;
+      free (old);
+    }
+}
+
+/* addGccArg - adds arg to the list of gcc arguments.  */
+
+static void
+addGccArg (char *arg)
+{
+  if (args == NULL)
+    args = strdup (arg);
+  else
+    {
+      char *old = args;
+      char *newarg = (char *)malloc (strlen (old) + strlen (arg) + 1 + 1);
+      strcpy (newarg, old);
+      strcat (newarg, " ");
+      strcat (newarg, arg);
+      args = newarg;
+      free (old);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+
+  if (argc >= 3)
+    {
+      if (strcmp (argv[1], "-l") == 0)
+	LinkCommandLine = TRUE;
+      else if (strcmp (argv[1], "-s") == 0)
+	LinkCommandLine = FALSE;
+      else
+        {
+          fprintf (stderr, "Usage: mklink (-l|-s) [--langc|--langc++] [--pg|-p] "
+                           "[--lib library] [--main name] [--exit] --name "
+                           "filename <modulelistfile>\n");
+          fprintf (stderr, "       must supply -l or -s option\n");
+          exit (1);
+        }
+      ProfilePCommand = FALSE;
+      ProfilePGCommand = FALSE;
+      i = 2;
+      while (i < argc - 1)
+        {
+          if (strcmp (argv[i], "--langc++") == 0)
+	    langC = FALSE;
+          else if (strcmp (argv[i], "--langc") == 0)
+	    langC = TRUE;
+          else if (strncmp (argv[i], "-f", 2) == 0)
+	    addGccArg (argv[i]);
+          else if (strcmp (argv[i], "--pg") == 0)
+	    ProfilePGCommand = TRUE;
+          else if (strcmp (argv[i], "-p") == 0)
+	    ProfilePCommand = TRUE;
+          else if (strcmp (argv[i], "--exit") == 0)
+	    ExitNeeded = FALSE;
+          else if (strcmp (argv[i], "--lib") == 0)
+            {
+              i++;
+              addLibrary (argv[i]);
+            }
+          else if (strcmp (argv[i], "--main") == 0)
+            {
+              i++;
+              NameOfMain = argv[i];
+            }
+          else if (strcmp (argv[i], "--name") == 0)
+            {
+              i++;
+              NameOfFile = argv[i];
+            }
+          i++;
+        }
+      ParseFile (argv[i]);
+    }
+  else
+    {
+      fprintf (stderr, "Usage: mklink (-l|-s) [--gcc|--g++] [--pg|-p] [--lib "
+                       "library] [--main name] [--exit] --name filename "
+                       "<modulelistfile>\n");
+      exit (1);
+    }
+  if (NameOfFile == NULL)
+    {
+      fprintf (stderr, "mklink must have a --name argument\n");
+      fprintf (stderr, "Usage: mklink (-l|-s) [--gcc|--g++] [--pg|-p] [--lib "
+                       "library] [--main name] [--exit] --name filename "
+                       "<modulelistfile>\n");
+      exit (1);
+    }
+  exit (0);
+}
+
+/* ParseFile - parses the input file and generates the output file.  */
+
+static void
+ParseFile (char *Name)
+{
+  FindSource (Name);
+  OpenOutputFile ();
+  if (LinkCommandLine)
+    ParseFileLinkCommand ();
+  else
+    ParseFileStartup ();
+  CloseFile ();
+}
+
+/* ParseFileLinkCommand - generates the link command.  */
+
+static void
+ParseFileLinkCommand (void)
+{
+  char name[MAX_FILE_NAME];
+  char *s = NULL;
+  char *l = NULL;
+  char *c = NULL;
+
+  s = getenv ("CC");
+  if (s == NULL)
+    {
+      if (langC)
+        printf ("gcc -g ");
+      else
+        printf ("g++ -g ");
+    }
+  else
+    printf ("%s -g ", s);
+
+  if (args != NULL)
+    printf ("%s ", args);
+
+  l = getenv ("LDFLAGS");
+  if (l != NULL)
+    printf ("%s ", l);
+
+  c = getenv ("CFLAGS");
+  if (c != NULL)
+    printf ("%s ", c);
+
+  if (ProfilePGCommand)
+    printf (" -pg");
+  else if (ProfilePCommand)
+    printf (" -p");
+
+  while (PutChar (GetChar ()) != (char)EOF)
+    {
+      CopyUntilEolInto (name);
+#if defined(XENIX)
+      name[10] = (char)0; /* truncate object file name.  */
+#endif
+      if ((strlen (name) > 0) && (name[0] != '#'))
+        FindObject (name);
+    }
+  printf (" %s\n", libraries);
+}
+
+/* FindObject - searches the M2PATH variable to find the object file.
+   If it finds the object file it prints it to stdout otherwise it
+   writes an error on stderr.  */
+
+static void
+FindObject (char *Name)
+{
+  char m2search[4096];
+  char m2path[4096];
+  char name[4096];
+  char exist[4096];
+  int s, p;
+
+  if (getenv ("M2PATH") == NULL)
+    strcpy (m2path, ".");
+  else
+    strcpy (m2path, getenv ("M2PATH"));
+
+  snprintf (name, sizeof (name), "%s.o", Name);
+  p = 0;
+  while (m2path[p] != (char)0)
+    {
+      s = 0;
+      while ((m2path[p] != (char)0) && (m2path[p] != ' '))
+        {
+          m2search[s] = m2path[p];
+          s++;
+          p++;
+        }
+      if (m2path[p] == ' ')
+	p++;
+      m2search[s] = (char)0;
+      snprintf (exist, sizeof (exist), "%s/%s", m2search, name);
+      if (IsExists (exist))
+        {
+          printf (" %s", exist);
+          return;
+        }
+    }
+  fprintf (stderr, "cannot find %s\n", name);
+}
+
+/* IsExists - returns true if a file, Name, exists.  It returns false
+   otherwise.  */
+
+static int
+IsExists (char *Name)
+{
+  struct stat buf;
+
+  return (stat (Name, &buf) == 0);
+}
+
+/* add_function - adds a name to the list of functions, in order.  */
+
+void
+add_function (char *name)
+{
+  functList *p = (functList *)malloc (sizeof (functList));
+  p->functname = (char *)malloc (strlen (name) + 1);
+  strcpy (p->functname, name);
+
+  if (head == NULL)
+    {
+      head = p;
+      tail = p;
+      p->next = NULL;
+    }
+  else
+    {
+      tail->next = p;
+      tail = p;
+      tail->next = NULL;
+    }
+}
+
+static void
+GenerateInitCalls (functList *p)
+{
+  while (p != NULL)
+    {
+      printf ("   _M2_%s_init (argc, argv, envp);\n", p->functname);
+      p = p->next;
+    }
+}
+
+static void
+GenerateFinishCalls (functList *p)
+{
+  if (p->next != NULL)
+    GenerateFinishCalls (p->next);
+  printf ("   _M2_%s_finish (argc, argv, envp);\n", p->functname);
+}
+
+static void
+GeneratePrototypes (functList *p)
+{
+  while (p != NULL)
+    {
+      if (langC)
+        {
+          printf ("extern void _M2_%s_init (int argc, char *argv[], char *envp[]);\n",
+                  p->functname);
+          printf ("extern void _M2_%s_finish (int argc, char *argv[], char *envp[]);\n",
+                  p->functname);
+        }
+      else
+        {
+          printf ("extern \"C\" void _M2_%s_init (int argc, char *argv[], char *envp[]);\n",
+                  p->functname);
+          printf ("extern \"C\" void _M2_%s_finish (int argc, char *argv[], char *envp[]);\n",
+                  p->functname);
+        }
+      p = p->next;
+    }
+}
+
+/* ParseFileStartup - generates the startup code.  */
+
+static void
+ParseFileStartup (void)
+{
+  char name[MAX_FILE_NAME];
+  functList *p;
+
+  while (PutChar (GetChar ()) != (char)EOF)
+    {
+      CopyUntilEolInto (name);
+      if ((strlen (name) > 0) && (strcmp (name, "mod_init") != 0)
+          && (name[0] != '#'))
+	add_function (name);
+    }
+  GeneratePrototypes (head);
+  printf ("extern");
+  if (!langC)
+    printf (" \"C\"");
+  printf (" void _exit(int);\n");
+
+  printf ("\n\nint %s(int argc, char *argv[], char *envp[])\n", NameOfMain);
+  printf ("{\n");
+  GenerateInitCalls (head);
+  GenerateFinishCalls (head);
+  if (ExitNeeded)
+    printf ("   _exit(0);\n");
+  printf ("   return(0);\n");
+  printf ("}\n");
+}
+
+/* OpenOutputFile - shut down stdout and open the new mod_init.c */
+
+static void
+OpenOutputFile (void)
+{
+  if (strcmp (NameOfFile, "-") != 0)
+    {
+      if (close (STDOUT) != 0)
+        {
+          ERROR ("Unable to close stdout");
+          exit (1);
+        }
+      OutputFile = creat (NameOfFile, 0666);
+      if (OutputFile != STDOUT)
+        {
+          ERROR ("Expected that the file descriptor should be 1");
+        }
+    }
+}
+
+/* CloseFile - flush and close the file.  */
+
+static void
+CloseFile (void)
+{
+#if 0
+  fflush(stdout);
+  if (close(STDOUT) != 0) {
+    ERROR("Unable to close our output file"); exit(1);
+  }
+#endif
+}
+
+/* CopyUntilEof - copies from the current input marker until ENDOFILE
+   is reached.  */
+
+static void
+CopyUntilEof (void)
+{
+  char ch;
+
+  while ((ch = GetChar ()) != ENDOFILE)
+    putchar (ch);
+}
+
+/* CopyUntilEol - copies from the current input marker until '\n' is
+   reached.  */
+
+static void
+CopyUntilEol (void)
+{
+  char ch;
+
+  while (((ch = GetChar ()) != '\n') && (ch != (char)EOF))
+    putchar (ch);
+  if (ch == '\n')
+    putchar (ch);
+}
+
+/* CopyUntilEolInto - copies from the current input marker until '\n'
+   is reached into a Buffer.  */
+
+static void
+CopyUntilEolInto (char *Buffer)
+{
+  char ch;
+  int i = 0;
+
+  while (((ch = GetChar ()) != '\n') && (ch != (char)EOF))
+    {
+      Buffer[i] = ch;
+      i++;
+    }
+  if ((ch == '\n') || (ch == (char)EOF))
+    Buffer[i] = (char)0;
+}
+
+/* IsSym - returns true if string, s, was found in the input stream.
+   The input stream is uneffected.  */
+
+static int
+IsSym (char *s)
+{
+  int i = 0;
+
+  while ((s[i] != (char)0) && (s[i] == PutChar (GetChar ())))
+    {
+      GetChar ();
+      i++;
+    }
+  if (s[i] == (char)0)
+    {
+      PushBack (s);
+      /* found s in input string.  */
+      return (TRUE);
+    }
+  else
+    {
+      /* push back the characters we have scanned.  */
+      if (i > 0)
+        {
+          do
+            {
+              i--;
+              PutChar (s[i]);
+            }
+          while (i > 0);
+        }
+      return (FALSE);
+    }
+}
+
+/* SymIs - returns true if string, s, was found in the input stream.
+   The token s is consumed from the input stream.  */
+
+static int
+SymIs (char *s)
+{
+  int i = 0;
+
+  while ((s[i] != (char)0) && (s[i] == PutChar (GetChar ())))
+    {
+      GetChar ();
+      i++;
+    }
+  if (s[i] == (char)0)
+    {
+      /* found s in input string.  */
+      return (TRUE);
+    }
+  else
+    {
+      /* push back the characters we have scanned.  */
+      if (i > 0)
+        {
+          do
+            {
+              i--;
+              PutChar (s[i]);
+            }
+          while (i > 0);
+        }
+      return (FALSE);
+    }
+}
+
+/* FindString - keeps on reading input until a string, String, is
+   matched.  If end of file is reached then FALSE is returned, otherwise
+   TRUE is returned.  */
+
+static int
+FindString (char *String)
+{
+  int StringIndex = 0;
+  int Found = FALSE;
+  int eof = FALSE;
+  char ch;
+
+  while ((!Found) && (!eof))
+    {
+      if (String[StringIndex] == (char)0)
+	/* must have found string.  */
+	Found = TRUE;
+      else
+        {
+          ch = GetChar ();
+          eof = (ch == ENDOFILE);
+          if (ch == String[StringIndex])
+	    StringIndex++;
+          else
+	    StringIndex = 0;
+        }
+    }
+  return (Found);
+}
+
+/* GetNL - keeps on reading input from until a new line is found.  */
+
+static void
+GetNL (void)
+{
+  char ch;
+
+  while ((ch = GetChar ()) != '\n')
+    putchar (ch);
+  putchar ('\n');
+}
+
+/* GetChar - returns the current character in input.  */
+
+static char
+GetChar (void)
+{
+  char ch;
+
+  if (StackPtr > 0)
+    {
+      StackPtr--;
+      return (Stack[StackPtr]);
+    }
+  else
+    {
+      if (GetSingleChar (&ch))
+	return (ch);
+      else
+	return (ENDOFILE);
+    }
+}
+
+#define MAXBUF 0x1000
+static int Pointer = 0;
+static int AmountRead = 0;
+static char Buffer[MAXBUF];
+
+/* ResetBuffer - resets the buffer information to an initial state.  */
+
+static void
+ResetBuffer (void)
+{
+  StackPtr = 0;
+  Pointer = 0;
+  AmountRead = 0;
+}
+
+/* GetSingleChar - gets a single character from input.  TRUE is
+   returned upon success.  */
+
+static int
+GetSingleChar (char *ch)
+{
+  if (Pointer == AmountRead)
+    {
+      AmountRead = read (CurrentFile, &Buffer, MAXBUF);
+      if (AmountRead < 0)
+	AmountRead = 0;
+      Pointer = 0;
+    }
+  if (Pointer == AmountRead)
+    {
+      *ch = ENDOFILE;
+      return (FALSE);
+    }
+  else
+    {
+      *ch = Buffer[Pointer];
+      Pointer++;
+      return (TRUE);
+    }
+}
+
+/* InRange - returns true if Element is within the range Min..Max.  */
+
+static int
+InRange (int Element, unsigned int Min, unsigned int Max)
+{
+  return ((Element >= Min) && (Element <= Max));
+}
+
+/* PutChar - pushes a character back onto input.  This character is
+   also returned.  */
+
+static char
+PutChar (char ch)
+{
+  if (StackPtr < MAXSTACK)
+    {
+      Stack[StackPtr] = ch;
+      StackPtr++;
+    }
+  else
+    {
+      ERROR ("Stack overflow in PutChar");
+    }
+  return (ch);
+}
+
+/* IsSpace - returns true if character, ch, is a space.  */
+
+static int
+IsSpace (char ch)
+{
+  return ((ch == ' ') || (ch == '\t'));
+}
+
+/* SkipSpaces - eats up spaces in input.  */
+
+static void
+SkipSpaces (void)
+{
+  while (IsSpace (PutChar (GetChar ())))
+    putchar (GetChar ());
+}
+
+/* SilentSkipSpaces - eats up spaces in input.  */
+
+static void
+SilentSkipSpaces (void)
+{
+  char ch;
+
+  while (IsSpace (PutChar (GetChar ())))
+    ch = GetChar (); /* throw away character.  */
+}
+
+/* SkipText - skips ascii text, it does not skip white spaces.  */
+
+static void
+SkipText (void)
+{
+  while (!IsSpace (PutChar (GetChar ())))
+    putchar (GetChar ());
+}
+
+/* SilentSkipText - skips ascii text, it does not skip white spaces.  */
+
+static void
+SilentSkipText (void)
+{
+  char ch;
+
+  while (!IsSpace (PutChar (GetChar ())))
+    ch = GetChar (); /* throw away character.  */
+}
+
+/* PushBack - pushes a string, backwards onto the input stack.  */
+
+static void
+PushBack (char *s)
+{
+  int i;
+
+  i = strlen (s);
+  while (i > 0)
+    {
+      i--;
+      PutChar (s[i]);
+    }
+}
+
+/* IsDigit - returns true if a character, ch, is a decimal digit.  */
+
+static int
+IsDigit (char ch)
+{
+  return (((ch >= '0') && (ch <= '9')));
+}
+
+/* GetName - returns the next name found.  */
+
+static void
+GetName (char *Name)
+{
+  int i;
+  char ch;
+
+  SkipSpaces ();
+  ch = GetChar ();
+  i = 0;
+  while (!IsSpace (ch))
+    {
+      Name[i] = ch;
+      i++;
+      ch = GetChar ();
+    }
+  Name[i] = '\0';
+}
+
+/* FindSource - open source file on StdIn.  */
+
+static void
+FindSource (char *Name)
+{
+  if (close (STDIN) != 0)
+    {
+      ERROR ("close on STDIN failed");
+    }
+  CurrentFile = open (Name, O_RDONLY);
+  if (CurrentFile < 0)
+    {
+      perror ("failed to open file");
+      exit (1);
+    }
+  if (CurrentFile != STDIN)
+    {
+      ERROR ("Expecting file descriptor value of 1");
+    }
+}
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/tools-src/def2texi.py
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/def2texi.py	2022-10-07 20:21:18.682097332 +0100
@@ -0,0 +1,423 @@
+#!/usr/bin/env python3
+
+# def2texi.py creates texi library documentation for all exported procedures.
+# Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+# 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 COPYING.  If not, write to the
+# Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import sys
+import os
+import glob
+import getopt
+
+libraryClassifications = [['gm2-libs','Base libraries',
+                           'Basic M2F compatible libraries'],
+                          ['gm2-libs-pim','PIM and Logitech 3.0 Compatible',
+                           'PIM and Logitech 3.0 compatible libraries'],
+                          ['gm2-libs-coroutines','PIM coroutine support',
+                           'PIM compatible process support'],
+                          ['gm2-libs-iso','M2 ISO Libraries',
+                           'ISO defined libraries']]
+
+def initState ():
+    global inVar, inType, inConst
+    inVar, inType, inConst = False, False, False
+
+
+#
+#  displayLibraryClass - displays a node for a library directory and invokes
+#                        a routine to summarize each module
+#
+
+def displayLibraryClass():
+    global buildDir, up
+    previous = ""
+
+    next=libraryClassifications[1][1]
+    i = 0
+    l = libraryClassifications[i]
+
+    while True:
+        print("@node " + l[1] + ", " + next + ", " + previous + ", " + up)
+        print("@section " + l[1])
+        print("")
+        displayModules(l[1], l[0], buildDir, sourceDir)
+        print("")
+        print("@c ---------------------------------------------------------------------")
+        previous = l[1]
+        i += 1
+        if i == len(libraryClassifications):
+            break
+        l = libraryClassifications[i]
+        if i+1 == len(libraryClassifications):
+            next = ""
+        else:
+            next = libraryClassifications[i+1][1]
+
+#
+#  displayMenu - displays the top level menu for library documentation
+#
+
+def displayMenu():
+    print("@menu")
+    for l in libraryClassifications:
+        print("* " + l[1] + "::" + l[2])
+    print("@end menu")
+
+    print("\n")
+    print("@c =====================================================================")
+    print("\n")
+
+
+#
+#  removeInitialComments - removes any (* *) at the top of the definition module
+#
+
+def removeInitialComments (file, line):
+    while (str.find(line, "*)") == -1):
+        line = file.readline()
+
+#
+#  removeFields - removes Author/Date/Last edit/SYSTEM/Revision fields from a comment within the start
+#                 of a definition module
+#
+
+def removeFields (file, line):
+    while (str.find(line, "*)") == -1):
+        if (str.find(line, "Author") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "Last edit") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "LastEdit") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "Last update") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "Date") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "Title") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "Revision") != -1) and (str.find(line, ":") != -1):
+            line = file.readline()
+        elif (str.find(line, "System") != -1) and (str.find(line, ":") != -1) and (str.find(line, "Description:") == -1):
+            line = file.readline()
+        elif (str.find(line, "SYSTEM") != -1) and (str.find(line, ":") != -1) and (str.find(line, "Description:") == -1):
+            line = file.readline()
+        else:
+           print(str.replace(str.replace(str.rstrip(line),
+                                            "{", "@{"), "}", "@}"))
+           line = file.readline()
+    print(str.rstrip(line))
+
+
+#
+#  checkIndex
+#
+
+def checkIndex (line):
+    global inVar, inType, inConst
+
+    words = str.split(line)
+    procedure = ""
+    if (len(words)>1) and (words[0] == "PROCEDURE"):
+        inConst = False
+        inType = False
+        inVar = False
+        if (words[1] == "__BUILTIN__") and (len(words)>2):
+            procedure = words[2]
+        else:
+            procedure = words[1]
+
+    if (len(line)>1) and (line[0:2] == '(*'):
+        inConst = False
+        inType = False
+        inVar = False
+    elif line == "VAR":
+        inConst = False
+        inVar = True
+        inType = False
+        return
+    elif line == "TYPE":
+        inConst = False
+        inType = True
+        inVar = False
+        return
+    elif line == "CONST":
+        inConst = True
+        inType = False
+        inVar = False
+
+    if inVar:
+        words = str.split(line, ',')
+        for word in words:
+            word = str.lstrip(word)
+            if word != "":
+                if str.find(word, ':') == -1:
+                    print("@findex " + word + " (var)")
+                elif len(word)>0:
+                    var = str.split(word, ':')
+                    if len(var)>0:
+                        print("@findex " + var[0] + " (var)")
+
+    if inType:
+        words = str.lstrip(line)
+        if str.find(words, '=') != -1:
+            word = str.split(words, "=")
+            if (len(word[0])>0) and (word[0][0] != '_'):
+                print("@findex " + str.rstrip(word[0]) + " (type)")
+        else:
+            word = str.split(words)
+            if (len(word)>1) and (word[1] == ';'):
+                # hidden type
+                if (len(word[0])>0) and (word[0][0] != '_'):
+                    print("@findex " + str.rstrip(word[0]) + " (type)")
+
+    if inConst:
+        words = str.split(line, ';')
+        for word in words:
+            word = str.lstrip(word)
+            if word != "":
+                if str.find(word, '=') != -1:
+                    var = str.split(word, '=')
+                    if len(var)>0:
+                        print("@findex " + var[0] + " (const)")
+
+    if procedure != "":
+        name = str.split(procedure, "(")
+        if name[0] != "":
+            proc = name[0]
+            if proc[-1] == ";":
+                proc = proc[:-1]
+            if proc != "":
+                print("@findex " + proc)
+
+
+#
+#  parseDefinition
+#
+
+def parseDefinition (dir, source, build, file, needPage):
+    print("")
+    f = open(findFile(dir, build, source, file), 'r')
+    initState()
+    line = f.readline()
+#   while (str.find(line, "(*") != -1):
+    while (str.find(line, "(*") != -1):
+        removeInitialComments(f, line)
+        line = f.readline()
+
+    while (str.find(line, "DEFINITION") == -1):
+        line = f.readline()
+
+    print("@example")
+    print(str.rstrip(line))
+    line = f.readline()
+    if len(str.rstrip(line)) == 0:
+        print(str.replace(str.replace(str.rstrip(line),
+                                            "{", "@{"), "}", "@}"))
+        line = f.readline()
+        if (str.find(line, "(*") != -1):
+            removeFields(f, line)
+        else:
+            print(str.rstrip(line))
+    else:
+        print(str.rstrip(line))
+
+    line = f.readline()
+    while line:
+        line = str.rstrip(line)
+        checkIndex(line)
+        print(str.replace(str.replace(line, "{", "@{"), "}", "@}"))
+        line = f.readline()
+    print("@end example")
+    if needPage:
+        print("@page")
+    f.close()
+
+def parseModules (up, dir, build, source, listOfModules):
+    previous = ""
+    i = 0
+    if len(listOfModules)>1:
+        next = dir + "/" + listOfModules[1][:-4]
+    else:
+        next = ""
+
+    while i<len(listOfModules):
+       print("@node " + dir + "/" + listOfModules[i][:-4] + ", " + next + ", " + previous + ", " + up)
+       print("@subsection " + dir + "/" + listOfModules[i][:-4])
+       parseDefinition(dir, source, build, listOfModules[i], True)
+       print("\n")
+       previous = dir + "/" + listOfModules[i][:-4]
+       i = i + 1
+       if i+1<len(listOfModules):
+           next = dir + "/" + listOfModules[i+1][:-4]
+       else:
+           next = ""
+
+
+#
+#  doCat - displays the contents of file, name, to stdout
+#
+
+def doCat (name):
+    file = open(name, 'r')
+    line = file.readline()
+    while line:
+        print(str.rstrip(line))
+        line = file.readline()
+    file.close()
+
+
+#
+#  moduleMenu - generates a simple menu for all definition modules
+#               in dir
+#
+
+def moduleMenu (dir, build, source):
+    print("@menu")
+    listOfFiles = []
+    if os.path.exists(os.path.join(source, dir)):
+        listOfFiles += os.listdir(os.path.join(source, dir))
+    if os.path.exists(os.path.join(source, dir)):
+        listOfFiles += os.listdir(os.path.join(build, dir))
+    listOfFiles = list(dict.fromkeys(listOfFiles).keys())
+    listOfFiles.sort()
+    for file in listOfFiles:
+        if foundFile(dir, build, source, file):
+            if (len(file)>4) and (file[-4:] == '.def'):
+                print("* " + dir + "/" + file[:-4] + "::" + file)
+    print("@end menu")
+    print("\n")
+
+
+#
+#  checkDirectory - returns True if dir exists in either build or source.
+#
+
+def checkDirectory (dir, build, source):
+    if os.path.isdir(build) and os.path.exists(os.path.join(build, dir)):
+        return True
+    elif os.path.isdir(source) and os.path.exists(os.path.join(source, dir)):
+        return True
+    else:
+        return False
+
+
+#
+#  foundFile - return True if file is found in build/dir/file or source/dir/file.
+#
+
+def foundFile (dir, build, source, file):
+    name = os.path.join(os.path.join(build, dir), file)
+    if os.path.exists(name):
+        return True
+    name = os.path.join(os.path.join(source, dir), file)
+    if os.path.exists(name):
+        return True
+    return False
+
+
+#
+#  findFile - return the path to file searching in build/dir/file first then source/dir/file.
+#
+
+def findFile (dir, build, source, file):
+    name1 = os.path.join(os.path.join(build, dir), file)
+    if os.path.exists(name1):
+        return name1
+    name2 = os.path.join(os.path.join(source, dir), file)
+    if os.path.exists(name2):
+        return name2
+    print("file cannot be found in either " + name1 + " or " + name2)
+    os.sys.exit(1)
+
+
+#
+#  displayModules - walks though the files in dir and parses
+#                   definition modules and includes README.texi
+#
+
+def displayModules(up, dir, build, source):
+    if checkDirectory(dir, build, source):
+        if foundFile(dir, build, source, "README.texi"):
+            doCat(findFile(dir, build, source, "README.texi"))
+
+        moduleMenu(dir, build, source)
+        listOfFiles = []
+        if os.path.exists(os.path.join(source, dir)):
+            listOfFiles += os.listdir(os.path.join(source, dir))
+        if os.path.exists(os.path.join(source, dir)):
+            listOfFiles += os.listdir(os.path.join(build, dir))
+        listOfFiles = list(dict.fromkeys(listOfFiles).keys())
+        listOfFiles.sort()
+        listOfModules = []
+        for file in listOfFiles:
+            if foundFile(dir, build, source, file):
+                if (len(file)>4) and (file[-4:] == '.def'):
+                    listOfModules += [file]
+        listOfModules.sort()
+        parseModules(up, dir, build, source, listOfModules)
+    else:
+        print("directory " + dir + " not found in either " + build + " or " + source)
+
+
+def displayCopyright ():
+    print("@c Copyright (C) 2000-2022 Free Software Foundation, Inc.")
+    print("@c This file is part of GNU Modula-2.")
+    print("""
+@c Permission is granted to copy, distribute and/or modify this document
+@c under the terms of the GNU Free Documentation License, Version 1.2 or
+@c any later version published by the Free Software Foundation.
+""")
+
+def Usage():
+    print("def2texi.py [-h][-bbuilddir][-uupnode][-ffilename]")
+
+def collectArgs():
+    buildDir="."
+    sourceDir="."
+    filename=""
+    up=""
+    try:
+        optlist, list = getopt.getopt(sys.argv[1:],':hb:f:s:u:')
+    except getopt.GetoptError:
+        Usage()
+        os.sys.exit(1)
+    for opt in optlist:
+        if opt[0] == '-h':
+            Usage()
+        if opt[0] == '-b':
+            buildDir = opt[1]
+        if opt[0] == '-f':
+            filename = opt[1]
+        if opt[0] == '-s':
+            sourceDir = opt[1]
+        if opt[0] == '-u':
+            up = opt[1]
+    return buildDir, sourceDir, filename, up
+
+
+buildDir, sourceDir, filename, up = collectArgs()
+
+if filename == "":
+    displayCopyright()
+    displayMenu()
+    displayLibraryClass()
+else:
+    parseDefinition('.', sourceDir, buildDir, filename, False)
