public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] 16/19 modula2 front end: bootstrap and documentation tools
@ 2022-10-10 15:31 Gaius Mulley
  2022-10-13  9:12 ` Martin Liška
  2022-10-20 12:42 ` [PATCH] 16/19 " Martin Liška
  0 siblings, 2 replies; 13+ messages in thread
From: Gaius Mulley @ 2022-10-10 15:31 UTC (permalink / raw)
  To: gcc-patches

 

This patch set contains the bootstrap linking tool as well as python3
scripts to automatically generate texi libraries section of the gm2
documentation.  In the fullness of time this will be changed to emit
sphinx.

 
------8<----------8<----------8<----------8<----------8<----------8<---- 
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)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] 16/19 modula2 front end: bootstrap and documentation tools
  2022-10-10 15:31 [PATCH] 16/19 modula2 front end: bootstrap and documentation tools Gaius Mulley
@ 2022-10-13  9:12 ` Martin Liška
  2022-10-14 12:10   ` Gaius Mulley
  2022-10-20 12:42 ` [PATCH] 16/19 " Martin Liška
  1 sibling, 1 reply; 13+ messages in thread
From: Martin Liška @ 2022-10-13  9:12 UTC (permalink / raw)
  To: Gaius Mulley, gcc-patches

On 10/10/22 17:31, Gaius Mulley via Gcc-patches wrote:
>  
> 

Hi!

> This patch set contains the bootstrap linking tool as well as python3
> scripts to automatically generate texi libraries section of the gm2
> documentation.  In the fullness of time this will be changed to emit
> sphinx.

Yep, looking forward to it. I'm going to write an email with Sphinx transition
schedule once Sphinx 5.3 gets released (should happen during the upcoming weekend).

I have general comments about the Python scripts:

1) please follow the Python coding style and not the GCC one (I'm going to document
it in https://gcc.gnu.org/codingconventions.html under a new Python section).
The easiest approach is using flake8 and the following plugins:

python3-flake8, python3-flake8-builtins, python3-flake8-bugbear, python3-flake8-import-order, python3-flake8-quotes

plus, you might want to come up with a setup.cfg like we have in:
./maintainer-scripts/setup.cfg

> 
>  
> ------8<----------8<----------8<----------8<----------8<----------8<---- 
> 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))

please use pathlib.Path(...).stem

> +        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 = ""

Please unify "" and '', you only apostrophes.

> +            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')

use 'with open(...) as outfile:'
https://docs.python.org/3/reference/compound_stmts.html#the-with-statement
   

> +        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)

shutil.move

> +                return
> +            else:
> +                outfile.write(l[n])
> +                n += 1
> +        outfile.close()

... will be closed automatically by 'with' statement.

> +        sys.stdout.write("%s:1:1 needs a Copyright notice..\n" % file)
> +
> +
> +#
> +#  bashTidy - tidy up dates using '#' comment
> +#
> +
> +def bashTidy (file):

Better putting comments here in function body.

> +    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:

better 'Copyright (C)' in text, similarly at other places ..

> +        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 ()

line = line.strip()

> +                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 ()):

'r' is default

> +            while l != "":
> +                l = l.strip ()
> +                l = l.rstrip ()
> +                if inComment:
> +                    text += " "
> +                    pos = l.find (end)

better use https://docs.python.org/3/library/stdtypes.html?highlight=partition#str.partition

> +                    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)

f-string format might be better, but that's just a hint:
https://docs.python.org/3/reference/lexical_analysis.html#f-strings

> +            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:

I prefer 'if not start_date' (simiarly at other places).

> +            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):

Path(...).stem again would be better.

> +                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)

https://docs.python.org/3/library/argparse.html would be much better, you get arguments parsing for free.

> +
> +
> +#
> +#  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]

^^^ this will be done automatically.

Hope it's usefull.

Thanks,
Martin

> +
> +
> +#
> +#  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)


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] 16/19 modula2 front end: bootstrap and documentation tools
  2022-10-13  9:12 ` Martin Liška
@ 2022-10-14 12:10   ` Gaius Mulley
  2022-11-07 13:09     ` [PATCH v2 16/19] " Gaius Mulley
  0 siblings, 1 reply; 13+ messages in thread
From: Gaius Mulley @ 2022-10-14 12:10 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches

Martin Liška <mliska@suse.cz> writes:

>> This patch set contains the bootstrap linking tool as well as python3
>> scripts to automatically generate texi libraries section of the gm2
>> documentation.  In the fullness of time this will be changed to emit
>> sphinx.
>
> Yep, looking forward to it. I'm going to write an email with Sphinx transition
> schedule once Sphinx 5.3 gets released (should happen during the upcoming weekend).
>
> I have general comments about the Python scripts:
>
> 1) please follow the Python coding style and not the GCC one (I'm going to document
> it in https://gcc.gnu.org/codingconventions.html under a new Python section).
> The easiest approach is using flake8 and the following plugins:
>
> python3-flake8, python3-flake8-builtins, python3-flake8-bugbear,
> python3-flake8-import-order, python3-flake8-quotes

Hi Martin,

many thanks for the pointers to the style tool and python lint - I'll
reformat the code accordingly.

> plus, you might want to come up with a setup.cfg like we have in:
> ./maintainer-scripts/setup.cfg

yes sounds sensible.  Thanks for the detailed
observations/suggestions/improvements below - I agree with them all and
will fix/change the code and then repost the patch

regards,
Gaius


>> ------8<----------8<----------8<----------8<----------8<----------8<---- 
>> 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))
>
> please use pathlib.Path(...).stem

>
>> +        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 = ""
>
> Please unify "" and '', you only apostrophes.
>
>> +            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')
>
> use 'with open(...) as outfile:'
> https://docs.python.org/3/reference/compound_stmts.html#the-with-statement
>    
>
>> +        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)
>
> shutil.move
>
>> +                return
>> +            else:
>> +                outfile.write(l[n])
>> +                n += 1
>> +        outfile.close()
>
> ... will be closed automatically by 'with' statement.
>
>> +        sys.stdout.write("%s:1:1 needs a Copyright notice..\n" % file)
>> +
>> +
>> +#
>> +#  bashTidy - tidy up dates using '#' comment
>> +#
>> +
>> +def bashTidy (file):
>
> Better putting comments here in function body.
>
>> +    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:
>
> better 'Copyright (C)' in text, similarly at other places ..
>
>> +        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 ()
>
> line = line.strip()
>
>> +                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 ()):
>
> 'r' is default
>
>> +            while l != "":
>> +                l = l.strip ()
>> +                l = l.rstrip ()
>> +                if inComment:
>> +                    text += " "
>> +                    pos = l.find (end)
>
> better use https://docs.python.org/3/library/stdtypes.html?highlight=partition#str.partition
>
>> +                    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)
>
> f-string format might be better, but that's just a hint:
> https://docs.python.org/3/reference/lexical_analysis.html#f-strings
>
>> +            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:
>
> I prefer 'if not start_date' (simiarly at other places).
>
>> +            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):
>
> Path(...).stem again would be better.
>
>> +                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)
>
> https://docs.python.org/3/library/argparse.html would be much better, you get arguments parsing for free.
>
>> +
>> +
>> +#
>> +#  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]
>
> ^^^ this will be done automatically.
>
> Hope it's usefull.
>
> Thanks,
> Martin
>
>> +
>> +
>> +#
>> +#  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)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] 16/19 modula2 front end: bootstrap and documentation tools
  2022-10-10 15:31 [PATCH] 16/19 modula2 front end: bootstrap and documentation tools Gaius Mulley
  2022-10-13  9:12 ` Martin Liška
@ 2022-10-20 12:42 ` Martin Liška
  2022-10-28 13:05   ` Gaius Mulley
  1 sibling, 1 reply; 13+ messages in thread
From: Martin Liška @ 2022-10-20 12:42 UTC (permalink / raw)
  To: Gaius Mulley, gcc-patches

Hello.

I noticed the devel/modula-2 branch contains the following dead links:

- http://www.gccsummit.org/2006
- http://www.gccsummit.org/2010/speakers.php?types=LIGHTNING
- http://floppsie.comp.glam.ac.uk/Papers/paper23/gaius-mulley-gnu-m2.pdf
- http://floppsie.comp.glam.ac.uk/Papers/paper15/mulley-proc.pdf
- http://floppsie.comp.glam.ac.uk/Papers/paper22/gaius-gcc-cauldron-2016.pdf

Thanks,
Martin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] 16/19 modula2 front end: bootstrap and documentation tools
  2022-10-20 12:42 ` [PATCH] 16/19 " Martin Liška
@ 2022-10-28 13:05   ` Gaius Mulley
  0 siblings, 0 replies; 13+ messages in thread
From: Gaius Mulley @ 2022-10-28 13:05 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches

Martin Liška <mliska@suse.cz> writes:

> Hello.
>
> I noticed the devel/modula-2 branch contains the following dead links:
>
> - http://www.gccsummit.org/2006
> - http://www.gccsummit.org/2010/speakers.php?types=LIGHTNING
> - http://floppsie.comp.glam.ac.uk/Papers/paper23/gaius-mulley-gnu-m2.pdf
> - http://floppsie.comp.glam.ac.uk/Papers/paper15/mulley-proc.pdf
> - http://floppsie.comp.glam.ac.uk/Papers/paper22/gaius-gcc-cauldron-2016.pdf
>
> Thanks,
> Martin

many thanks - I will remove these,

regards,
Gaius

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-10-14 12:10   ` Gaius Mulley
@ 2022-11-07 13:09     ` Gaius Mulley
  2022-11-07 13:47       ` Martin Liška
  0 siblings, 1 reply; 13+ messages in thread
From: Gaius Mulley @ 2022-11-07 13:09 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches


Hi Martin,

here is the revised patch having applied all previous recommendations:

  https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603436.html
  
Is this ok now?  Thanks for the improvement suggestions (argparse
results in fewer lines of code :-)

regards,
Gaius

 
------8<----------8<----------8<----------8<----------8<----------8<---- 
diff -ruw /dev/null gcc-git-devel-modula2/mliska@suse.cz
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-11-05 17:33:53.685584357 +0000
@@ -0,0 +1,166 @@
+#!/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
+import sys
+import pathlib
+import shutil
+
+maxLineLength = 60
+
+COPYRIGHT = "Copyright (C)"
+
+
+def visitDir(directory, ext, func):
+    # visitDir - call func for each file below, dir, matching extension, ext.
+    listOfFiles = os.listdir(directory)
+    listOfFiles.sort()
+    for filename in listOfFiles:
+        path = pathlib.PurePath(filename)
+        full = os.path.join(directory, filename)
+        if path.is_file(full):
+            if path.suffix == ext:
+                func(full)
+        elif path.is_dir(full):
+            visitDir(full, ext, func)
+
+
+def isYear(year):
+    # isYear - returns True if, year, is legal.
+    if len(year) == 5:
+        year = year[:-1]
+    for c in year:
+        if not c.isdigit():
+            return False
+    return True
+
+
+def handleCopyright(outfile, lines, n, leader1, leader2):
+    # handleCopyright look for Copyright in the comment.
+    global maxLineLength
+    i = lines[n]
+    c = i.find(COPYRIGHT)+len(COPYRIGHT)
+    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
+
+
+def handleHeader(filename, leader1, leader2):
+    # handleHeader reads in the header of a file and inserts
+    # a line break around the Copyright dates.
+    print("------------------------------")
+    lines = open(filename, "r").readlines()
+    if len(lines) > 20:
+        with open("tmptidy", "w") as outfile:
+            n = 0
+            for i in lines:
+                if i.find("Copyright (C)") >= 0:
+                    outfile, n = handleCopyright(outfile, lines,
+                                                 n, leader1, leader2)
+                    outfile.writelines(lines[n:])
+                    outfile.close()
+                    print("-> mv tmptidy", filename)
+                    shutil.move("tmptidy", filename)
+                    return
+                else:
+                    outfile.write(lines[n])
+                    n += 1
+        sys.stdout.write("%s:1:1 needs a Copyright notice..\n" % filename)
+
+
+def bashTidy(filename):
+    # bashTidy - tidy up dates using "#" comment
+    handleHeader(filename, "#", " ")
+
+
+def cTidy(filename):
+    # cTidy - tidy up dates using "/* */" comments
+    handleHeader(filename, " ", "*")
+
+
+def m2Tidy(filename):
+    # m2Tidy - tidy up dates using "(* *)" comments
+    handleHeader(filename, " ", " ")
+
+
+def main():
+    # main - for each file extension call the appropriate tidy routine.
+    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-11-05 17:33:53.685584357 +0000
@@ -0,0 +1,548 @@
+#!/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 argparse
+import datetime
+import os
+import sys
+
+
+errorCount = 0
+seenFiles = []
+outputName = None
+
+ISO_COPYRIGHT = "Copyright ISO/IEC"
+COPYRIGHT = "Copyright (C)"
+GNU_PUBLIC_LICENSE = "GNU General Public License"
+GNU_LESSER_GENERAL = "GNU Lesser General"
+GCC_RUNTIME_LIB_EXC = "GCC Runtime Library Exception"
+VERSION_2_1 = "version 2.1"
+VERSION_2 = "version 2"
+VERSION_3 = "version 3"
+Licenses = {VERSION_2_1: "v2.1", VERSION_2: "v2", VERSION_3: "v3"}
+CONTRIBUTED_BY = "ontributed by"
+
+
+def printf(fmt, *args):
+    # printf - keeps C programmers happy :-)
+    print(str(fmt) % args, end=' ')
+
+
+def error(fmt, *args):
+    # error - issue an error message.
+    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]
+
+
+def analyseComment(text, f):
+    # analyseComment determine the license from the top comment.
+    start_date, end_date = None, None
+    contribution, summary, lic = None, None, None
+    if text.find(ISO_COPYRIGHT) > 0:
+        lic = "BSISO"
+        now = datetime.datetime.now()
+        for d in range(1984, now.year+1):
+            if text.find(str(d)) > 0:
+                if start_date is None:
+                    start_date = str(d)
+                end_date = str(d)
+        return start_date, end_date, "", "", lic
+    elif text.find(COPYRIGHT) > 0:
+        if text.find(GNU_PUBLIC_LICENSE) > 0:
+            lic = "GPL"
+        elif text.find(GNU_LESSER_GENERAL) > 0:
+            lic = "LGPL"
+        for license in Licenses.keys():
+            if text.find(license) > 0:
+                lic += Licenses[license]
+        if text.find(GCC_RUNTIME_LIB_EXC) > 0:
+            lic += "x"
+        now = datetime.datetime.now()
+        for d in range(1984, now.year+1):
+            if text.find(str(d)) > 0:
+                if start_date is None:
+                    start_date = str(d)
+                end_date = str(d)
+        if text.find(CONTRIBUTED_BY) > 0:
+            i = text.find(CONTRIBUTED_BY)
+            i += len(CONTRIBUTED_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
+
+
+def analyseHeaderWithoutTerminator(f, start):
+    text = ""
+    for count, l in enumerate(open(f).readlines()):
+        parts = l.split(start)
+        if len(parts) > 1:
+            line = start.join(parts[1:])
+            line = line.strip()
+            text += " "
+            text += line
+        elif (l.rstrip() != "") and (len(parts[0]) > 0):
+            return analyseComment(text, f), count
+    return [None, None, None, None, None], 0
+
+
+def analyseHeaderWithTerminator(f, start, end):
+    inComment = False
+    text = ""
+    for count, line in enumerate(open(f).readlines()):
+        while line != "":
+            line = line.strip()
+            if inComment:
+                text += " "
+                pos = line.find(end)
+                if pos >= 0:
+                    text += line[:pos]
+                    line = line[pos:]
+                    inComment = False
+                else:
+                    text += line
+                    line = ""
+            else:
+                pos = line.find(start)
+                if (pos >= 0) and (len(line) > len(start)):
+                    before = line[:pos].strip()
+                    if before != "":
+                        return analyseComment(text, f), count
+                    line = line[pos + len(start):]
+                    inComment = True
+                elif (line != "") and (line == end):
+                    line = ""
+                else:
+                    return analyseComment(text, f), count
+    return [None, None, None, None, None], 0
+
+
+def analyseHeader(f, start, end):
+    # analyseHeader -
+    if end is None:
+        return analyseHeaderWithoutTerminator(f, start)
+    else:
+        return analyseHeaderWithTerminator(f, start, end)
+
+
+def addStop(sentence):
+    # addStop - add a full stop to a sentance.
+    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 = {}
+templates["GPLv3"] = GPLv3
+templates["GPLv3x"] = GPLv3x
+templates["LGPLv3"] = LGPLv3
+templates["LGPLv2.1"] = LGPLv3
+templates["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 is not None:
+                fo.write(magic)
+                fo.write("\n")
+            text = templates[lic] % (summary, dates, contribution)
+            text = text.rstrip()
+        if end is 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 is 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):
+    text = "".join(open(f).readlines()[lines:])
+    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()
+
+
+def handleHeader(f, magic, start, end):
+    # handleHeader keep reading lines of file, f, looking for start, end
+    # sequences and comments inside.  The comments are checked for:
+    # date, contribution, summary
+    global errorCount
+
+    errorCount = 0
+    [start_date, end_date,
+     contribution, summary, lic], lines = analyseHeader(f, start, end)
+    if lic is None:
+        error("%s:1:no GPL found at the top of the file\n", f)
+    else:
+        if args.verbose:
+            printf("copyright: %s\n", lic)
+            if (start_date is not None) and (end_date is not None):
+                if start_date == end_date:
+                    printf("dates = %s\n", start_date)
+                else:
+                    printf("dates = %s-%s\n", start_date, end_date)
+            if summary is not None:
+                printf("summary: %s\n", summary)
+            if contribution is not None:
+                printf("contribution: %s\n", contribution)
+        if start_date is None:
+            error("%s:1:no date found in the GPL at the top of the file\n", f)
+        if args.contribution is None:
+            if contribution == "":
+                error("%s:1:no contribution found in the " +
+                      "GPL at the top of the file\n", f)
+            else:
+                contribution = args.contribution
+        if summary is None:
+            if args.summary == "":
+                error("%s:1:no single line summary found in the " +
+                      "GPL at the top of the file\n", f)
+            else:
+                summary = args.summary
+    if errorCount == 0:
+        now = datetime.datetime.now()
+        if args.no:
+            print(f, "suppressing change as requested: %s-%s %s"
+                  % (start_date, end_date, lic))
+        else:
+            if lic == "BSISO":
+                # don't change the BS ISO license!
+                pass
+            elif args.extensions:
+                lic = "GPLv3x"
+            elif args.gpl3:
+                lic = "GPLv3"
+            rewriteFile(f, magic, start, end, start_date,
+                        str(now.year), contribution, summary, lic, lines)
+    else:
+        printf("too many errors, no modifications will occur\n")
+
+
+def bashTidy(f):
+    # bashTidy tidy up dates using '#' comment
+    handleHeader(f, "#!/bin/bash", "#", None)
+
+
+def pythonTidy(f):
+    # pythonTidy tidy up dates using '#' comment
+    handleHeader(f, "#!/usr/bin/env python3", '#', None)
+
+
+def bnfTidy(f):
+    # bnfTidy tidy up dates using '--' comment
+    handleHeader(f, None, '--', None)
+
+
+def cTidy(f):
+    # cTidy tidy up dates using '/* */' comments
+    handleHeader(f, None, '/*', '*/')
+
+
+def m2Tidy(f):
+    # m2Tidy tidy up dates using '(* *)' comments
+    handleHeader(f, None, '(*', '*)')
+
+
+def inTidy(f):
+    # inTidy tidy up dates using '#' as a comment and check
+    # the first line for magic number.
+    first = open(f).readlines()[0]
+    if (len(first) > 0) and (first[:2] == "#!"):
+        # magic number found, use this
+        handleHeader(f, first, "#", None)
+    else:
+        handleHeader(f, None, "#", None)
+
+
+def doVisit(args, dirname, names):
+    # doVisit helper function to call func on every extension file.
+    global outputName
+    func, extension = args
+    for f in names:
+        if len(f) > len(extension) and f[-len(extension):] == extension:
+            outputName = f
+            func(os.path.join(dirname, f))
+
+
+def visitDir(startDir, ext, func):
+    # visitDir call func for each file in startDir which has ext.
+    global outputName, seenFiles
+    for dirName, subdirList, fileList in os.walk(startDir):
+        for fname in fileList:
+            if (len(fname) > len(ext)) and (fname[-len(ext):] == ext):
+                fullpath = os.path.join(dirName, fname)
+                outputName = fullpath
+                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]
+
+
+def findFiles():
+    # findFiles for each file extension call the appropriate tidy routine.
+    visitDir(args.recursive, '.h.in', cTidy)
+    visitDir(args.recursive, '.in', inTidy)
+    visitDir(args.recursive, '.sh', inTidy)
+    visitDir(args.recursive, '.py', pythonTidy)
+    visitDir(args.recursive, '.c', cTidy)
+    visitDir(args.recursive, '.h', cTidy)
+    visitDir(args.recursive, '.cc', cTidy)
+    visitDir(args.recursive, '.def', m2Tidy)
+    visitDir(args.recursive, '.mod', m2Tidy)
+    visitDir(args.recursive, '.bnf', bnfTidy)
+
+
+def handleArguments():
+    # handleArguments create and return the args object.
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-c", "--contribution",
+                        help="set the contribution string " +
+                        "at the top of the file.",
+                        default="", action="store")
+    parser.add_argument("-d", "--debug", help="turn on internal debugging.",
+                        default=False, action="store_true")
+    parser.add_argument("-f", "--force",
+                        help="force a check to insist that the " +
+                        "contribution, summary and GPL exist.",
+                        default=False, action="store_true")
+    parser.add_argument("-g", "--gplv3", help="change to GPLv3",
+                        default=False, action="store_true")
+    parser.add_argument("-o", "--outputfile", help="set the output file",
+                        default="-", action="store")
+    parser.add_argument("-r", "--recursive",
+                        help="recusively scan directory for known file " +
+                        "extensions (.def, .mod, .c, .h, .py, .in, .sh).",
+                        default=".", action="store")
+    parser.add_argument("-s", "--summary",
+                        help="set the summary line for the file.",
+                        default=None, action="store")
+    parser.add_argument("-u", "--update", help="update all dates.",
+                        default=False, action="store_true")
+    parser.add_argument("-v", "--verbose",
+                        help="display copyright, " +
+                        "date and contribution messages",
+                        action="store_true")
+    parser.add_argument("-x", "--extensions",
+                        help="change to GPLv3 with GCC runtime extensions.",
+                        default=False, action="store_true")
+    parser.add_argument("-N", "--no",
+                        help="do not modify any file.",
+                        action="store_true")
+    args = parser.parse_args()
+    return args
+
+
+def hasExt(name, ext):
+    # hasExt return True if, name, ends with, ext.
+    if len(name) > len(ext):
+        return name[-len(ext):] == ext
+    return False
+
+
+def singleFile(name):
+    # singleFile scan the single file for a GPL boilerplate which
+    # has a GPL, contribution field and a summary heading.
+    if hasExt(name, ".def") or hasExt(name, ".mod"):
+        m2Tidy(name)
+    elif hasExt(name, ".h") or hasExt(name, ".c") or hasExt(name, ".cc"):
+        cTidy(name)
+    elif hasExt(name, ".in"):
+        inTidy(name)
+    elif hasExt(name, ".sh"):
+        inTidy(name)  # uses magic number for actual sh/bash
+    elif hasExt(name, ".py"):
+        pythonTidy(name)
+
+
+def main():
+    # main - handleArguments and then find source files.
+    global args, outputName
+    args = handleArguments()
+    outputName = args.outputfile
+    if args.recursive:
+        findFiles()
+    elif args.inputfile is None:
+        print("an input file must be specified on the command line")
+    else:
+        singleFile(args.inputfile)
+    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-11-05 17:33:53.685584357 +0000
@@ -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-11-05 17:33:53.685584357 +0000
@@ -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-11-05 17:33:53.685584357 +0000
@@ -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-11-05 17:33:53.685584357 +0000
@@ -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/def2doc.py
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/tools-src/def2doc.py	2022-11-05 17:33:53.685584357 +0000
@@ -0,0 +1,419 @@
+#!/usr/bin/env python3
+
+# def2doc.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 argparse
+import os
+import sys
+
+BaseLibs = ["gm2-libs", "Base libraries", "Basic M2F compatible libraries"]
+
+PIMLogDesc = "PIM and Logitech 3.0 compatible libraries"
+PIMLog = ["gm2-libs-pim", "PIM and Logitech 3.0 Compatible", PIMLogDesc]
+PIMCorDesc = "PIM compatible process support"
+PIMCor = ["gm2-libs-coroutines", "PIM coroutine support", PIMCorDesc]
+ISOLibs = ["gm2-libs-iso", "M2 ISO Libraries", "ISO defined libraries"]
+
+libraryClassifications = [BaseLibs, PIMLog, PIMCor, ISOLibs]
+
+
+def initState():
+    global inVar, inType, inConst
+    inVar, inType, inConst = False, False, False
+
+
+def emitNode(name, nxt, previous, up):
+    if args.texinfo:
+        output.write("@node " + name + ", " + nxt + ", ")
+        output.write(previous + ", " + up + "\n")
+    elif args.sphinx:
+        output.write("@c @node " + name + ", " + nxt + ", ")
+        output.write(previous + ", " + up + "\n")
+
+
+def emitSection(name):
+    if args.texinfo:
+        output.write("@section " + name + "\n")
+    elif args.sphinx:
+        output.write(name + "\n")
+        output.write("=" * len(name) + "\n")
+
+
+def emitSubSection(name):
+    if args.texinfo:
+        output.write("@subsection " + name + "\n")
+    elif args.sphinx:
+        output.write(name + "\n")
+        output.write("-" * len(name) + "\n")
+
+
+def displayLibraryClass():
+    # displayLibraryClass displays a node for a library directory and invokes
+    # a routine to summarize each module.
+    global args
+    previous = ""
+    nxt = libraryClassifications[1][1]
+    i = 0
+    lib = libraryClassifications[i]
+    while True:
+        emitNode(lib[1], nxt, previous, args.up)
+        emitSection(lib[1])
+        output.write("\n")
+        displayModules(lib[1], lib[0], args.builddir, args.sourcedir)
+        output.write("\n")
+        output.write("@c " + "-" * 60 + "\n")
+        previous = lib[1]
+        i += 1
+        if i == len(libraryClassifications):
+            break
+        lib = libraryClassifications[i]
+        if i+1 == len(libraryClassifications):
+            nxt = ""
+        else:
+            nxt = libraryClassifications[i+1][1]
+
+
+def displayMenu():
+    # displayMenu displays the top level menu for library documentation.
+    output.write("@menu\n")
+    for lib in libraryClassifications:
+        output.write("* " + lib[1] + "::" + lib[2] + "\n")
+    output.write("@end menu\n")
+    output.write("\n")
+    output.write("@c " + "=" * 60 + "\n")
+    output.write("\n")
+
+
+def removeInitialComments(file, line):
+    # removeInitialComments removes any (* *) at the top
+    # of the definition module.
+    while (str.find(line, "*)") == -1):
+        line = file.readline()
+
+
+def removeableField(line):
+    # removeableField - returns True if a comment field should be removed
+    # from the definition module.
+    field_list = ["Author", "Last edit", "LastEdit", "Last update",
+                  "Date", "Title", "Revision"]
+    for field in field_list:
+        if (str.find(line, field) != -1) and (str.find(line, ":") != -1):
+            return True
+    ignore_list = ["System", "SYSTEM"]
+    for ignore_field in ignore_list:
+        if str.find(line, ignore_field) != -1:
+            if str.find(line, ":") != -1:
+                if str.find(line, "Description:") == -1:
+                    return True
+    return False
+
+
+def removeFields(file, line):
+    # removeFields removes Author/Date/Last edit/SYSTEM/Revision
+    # fields from a comment within the start of a definition module.
+    while (str.find(line, "*)") == -1):
+        if not removeableField(line):
+            output.write(str.replace(str.replace(str.rstrip(line),
+                                                 "{", "@{"), "}", "@}") + "\n")
+        line = file.readline()
+    output.write(str.rstrip(line) + "\n")
+
+
+def checkIndex(line):
+    # checkIndex - create an index entry for a PROCEDURE, TYPE, CONST or VAR.
+    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:
+                    output.write("@findex " + word + " (var)\n")
+                elif len(word) > 0:
+                    var = str.split(word, ":")
+                    if len(var) > 0:
+                        output.write("@findex " + var[0] + " (var)\n")
+
+    if inType:
+        words = str.lstrip(line)
+        if str.find(words, "=") != -1:
+            word = str.split(words, "=")
+            if (len(word[0]) > 0) and (word[0][0] != "_"):
+                output.write("@findex " + str.rstrip(word[0]) + " (type)\n")
+        else:
+            word = str.split(words)
+            if (len(word) > 1) and (word[1] == ";"):
+                # hidden type
+                if (len(word[0]) > 0) and (word[0][0] != "_"):
+                    output.write("@findex " + str.rstrip(word[0]))
+                    output.write(" (type)\n")
+    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:
+                        output.write("@findex " + var[0] + " (const)\n")
+    if procedure != "":
+        name = str.split(procedure, "(")
+        if name[0] != "":
+            proc = name[0]
+            if proc[-1] == ";":
+                proc = proc[:-1]
+            if proc != "":
+                output.write("@findex " + proc + "\n")
+
+
+def parseDefinition(dir, source, build, file, needPage):
+    # parseDefinition reads a definition module and creates
+    # indices for procedures, constants, variables and types.
+    output.write("\n")
+    with open(findFile(dir, build, source, file), "r") as f:
+        initState()
+        line = f.readline()
+        while (str.find(line, "(*") != -1):
+            removeInitialComments(f, line)
+            line = f.readline()
+        while (str.find(line, "DEFINITION") == -1):
+            line = f.readline()
+        output.write("@example\n")
+        output.write(str.rstrip(line) + "\n")
+        line = f.readline()
+        if len(str.rstrip(line)) == 0:
+            output.write("\n")
+            line = f.readline()
+            if (str.find(line, "(*") != -1):
+                removeFields(f, line)
+            else:
+                output.write(str.rstrip(line) + "\n")
+        else:
+            output.write(str.rstrip(line) + "\n")
+        line = f.readline()
+        while line:
+            line = str.rstrip(line)
+            checkIndex(line)
+            output.write(str.replace(str.replace(line, "{", "@{"), "}", "@}"))
+            output.write("\n")
+            line = f.readline()
+        output.write("@end example\n")
+        if needPage:
+            output.write("@page\n")
+
+
+def parseModules(up, dir, build, source, listOfModules):
+    previous = ""
+    i = 0
+    if len(listOfModules) > 1:
+        nxt = dir + "/" + listOfModules[1][:-4]
+    else:
+        nxt = ""
+    while i < len(listOfModules):
+        emitNode(dir + "/" + listOfModules[i][:-4], nxt, previous, up)
+        emitSubSection(dir + "/" + listOfModules[i][:-4])
+        parseDefinition(dir, source, build, listOfModules[i], True)
+        output.write("\n")
+        previous = dir + "/" + listOfModules[i][:-4]
+        i = i + 1
+        if i+1 < len(listOfModules):
+            nxt = dir + "/" + listOfModules[i+1][:-4]
+        else:
+            nxt = ""
+
+
+def doCat(name):
+    # doCat displays the contents of file, name, to stdout
+    with open(name, "r") as file:
+        line = file.readline()
+        while line:
+            output.write(str.rstrip(line) + "\n")
+            line = file.readline()
+
+
+def moduleMenu(dir, build, source):
+    # moduleMenu generates a simple menu for all definition modules
+    # in dir
+    output.write("@menu\n")
+    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"):
+                output.write("* " + dir + "/" + file[:-4] + "::" + file + "\n")
+    output.write("@end menu\n")
+    output.write("\n")
+
+
+def checkDirectory(dir, build, source):
+    # checkDirectory - returns True if dir exists in either build or 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
+
+
+def foundFile(dir, build, source, file):
+    # foundFile return True if file is found in build/dir/file or
+    # source/dir/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
+
+
+def findFile(dir, build, source, file):
+    # findFile return the path to file searching in build/dir/file
+    # first then source/dir/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
+    sys.stderr.write("file cannot be found in either " + name1)
+    sys.stderr.write(" or " + name2 + "\n")
+    os.sys.exit(1)
+
+
+def displayModules(up, dir, build, source):
+    # displayModules walks though the files in dir and parses
+    # definition modules and includes README.texi
+    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:
+        line = "directory " + dir + " not found in either "
+        line += build + " or " + source
+        sys.stderr.write(line + "\n")
+
+
+def displayCopyright():
+    output.write("@c Copyright (C) 2000-2022 Free Software Foundation, Inc.\n")
+    output.write("@c This file is part of GNU Modula-2.\n")
+    output.write("""
+@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 collectArgs():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-v", "--verbose", help="generate progress messages",
+                        action="store_true")
+    parser.add_argument("-b", "--builddir", help="set the build directory",
+                        default=".", action="store")
+    parser.add_argument("-f", "--inputfile", help="set the input file",
+                        default=None, action="store")
+    parser.add_argument("-o", "--outputfile", help="set the output file",
+                        default=None, action="store")
+    parser.add_argument("-s", "--sourcedir", help="set the source directory",
+                        default=".", action="store")
+    parser.add_argument("-t", "--texinfo",
+                        help="generate texinfo documentation",
+                        default=False, action="store_true")
+    parser.add_argument("-u", "--up", help="set the up node",
+                        default="", action="store")
+    parser.add_argument("-x", "--sphinx", help="generate sphinx documentation",
+                        default=False, action="store_true")
+    args = parser.parse_args()
+    return args
+
+
+def handleFile():
+    if args.inputfile is None:
+        displayCopyright()
+        displayMenu()
+        displayLibraryClass()
+    else:
+        parseDefinition(".", args.sourcedir, args.builddir,
+                        args.inputfile, False)
+
+
+def main():
+    global args, output
+    args = collectArgs()
+    if args.outputfile is None:
+        output = sys.stdout
+        handleFile()
+    else:
+        with open(args.outputfile, "w") as output:
+            handleFile()
+
+
+main()
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-11-07 13:01:28.329424600 +0000
@@ -0,0 +1,807 @@
+/* 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 ((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");
+    }
+}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-07 13:09     ` [PATCH v2 16/19] " Gaius Mulley
@ 2022-11-07 13:47       ` Martin Liška
  2022-11-08 13:22         ` Gaius Mulley
  0 siblings, 1 reply; 13+ messages in thread
From: Martin Liška @ 2022-11-07 13:47 UTC (permalink / raw)
  To: Gaius Mulley; +Cc: gcc-patches

On 11/7/22 14:09, Gaius Mulley wrote:
> 
> Hi Martin,
> 
> here is the revised patch having applied all previous recommendations:
> 
>   https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603436.html

Hi.

>   
> Is this ok now?  Thanks for the improvement suggestions (argparse
> results in fewer lines of code :-)

Thanks, much better, however some comments are still not addressed:

1) I would prefer using ' instead of ":

$ flake8 ./gcc/m2/tools-src/tidydates.py
...
./gcc/m2/tools-src/tidydates.py:124:30: Q000 Double quotes found but single quotes preferred
./gcc/m2/tools-src/tidydates.py:127:27: Q000 Double quotes found but single quotes preferred
./gcc/m2/tools-src/tidydates.py:132:27: Q000 Double quotes found but single quotes preferred
./gcc/m2/tools-src/tidydates.py:133:33: Q000 Double quotes found but single quotes preferred
./gcc/m2/tools-src/tidydates.py:138:26: Q000 Double quotes found but single quotes preferred
./gcc/m2/tools-src/tidydates.py:143:28: Q000 Double quotes found but single quotes preferred

2) Python-names would be nicer:

def writeTemplate(fo, magic, start, end, dates, contribution, summary, lic):

def write_template(...)

3) def hasExt(name, ext) - please use Path from pathlib

4)         while (str.find(line, "(*") != -1):

'(*' in line
? Similarly elsewhere.

5) str.find(line, ...)

Use rather directly: line.find(...)

6) please use flake8:
https://gcc.gnu.org/codingconventions.html#python

Thanks,
Martin

P.S. I'm going to merge Sphinx branch this Wednesday, so then we should port your
conversion scripts to emit .rst instead of .texi.

> 
> regards,
> Gaius
> 
>  
> ------8<----------8<----------8<----------8<----------8<----------8<---- 
> diff -ruw /dev/null gcc-git-devel-modula2/mliska@suse.cz
> 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-11-05 17:33:53.685584357 +0000
> @@ -0,0 +1,166 @@
> +#!/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
> +import sys
> +import pathlib
> +import shutil
> +
> +maxLineLength = 60
> +
> +COPYRIGHT = "Copyright (C)"
> +
> +
> +def visitDir(directory, ext, func):
> +    # visitDir - call func for each file below, dir, matching extension, ext.
> +    listOfFiles = os.listdir(directory)
> +    listOfFiles.sort()
> +    for filename in listOfFiles:
> +        path = pathlib.PurePath(filename)
> +        full = os.path.join(directory, filename)
> +        if path.is_file(full):
> +            if path.suffix == ext:
> +                func(full)
> +        elif path.is_dir(full):
> +            visitDir(full, ext, func)
> +
> +
> +def isYear(year):
> +    # isYear - returns True if, year, is legal.
> +    if len(year) == 5:
> +        year = year[:-1]
> +    for c in year:
> +        if not c.isdigit():
> +            return False
> +    return True
> +
> +
> +def handleCopyright(outfile, lines, n, leader1, leader2):
> +    # handleCopyright look for Copyright in the comment.
> +    global maxLineLength
> +    i = lines[n]
> +    c = i.find(COPYRIGHT)+len(COPYRIGHT)
> +    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
> +
> +
> +def handleHeader(filename, leader1, leader2):
> +    # handleHeader reads in the header of a file and inserts
> +    # a line break around the Copyright dates.
> +    print("------------------------------")
> +    lines = open(filename, "r").readlines()
> +    if len(lines) > 20:
> +        with open("tmptidy", "w") as outfile:
> +            n = 0
> +            for i in lines:
> +                if i.find("Copyright (C)") >= 0:
> +                    outfile, n = handleCopyright(outfile, lines,
> +                                                 n, leader1, leader2)
> +                    outfile.writelines(lines[n:])
> +                    outfile.close()
> +                    print("-> mv tmptidy", filename)
> +                    shutil.move("tmptidy", filename)
> +                    return
> +                else:
> +                    outfile.write(lines[n])
> +                    n += 1
> +        sys.stdout.write("%s:1:1 needs a Copyright notice..\n" % filename)
> +
> +
> +def bashTidy(filename):
> +    # bashTidy - tidy up dates using "#" comment
> +    handleHeader(filename, "#", " ")
> +
> +
> +def cTidy(filename):
> +    # cTidy - tidy up dates using "/* */" comments
> +    handleHeader(filename, " ", "*")
> +
> +
> +def m2Tidy(filename):
> +    # m2Tidy - tidy up dates using "(* *)" comments
> +    handleHeader(filename, " ", " ")
> +
> +
> +def main():
> +    # main - for each file extension call the appropriate tidy routine.
> +    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-11-05 17:33:53.685584357 +0000
> @@ -0,0 +1,548 @@
> +#!/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 argparse
> +import datetime
> +import os
> +import sys
> +
> +
> +errorCount = 0
> +seenFiles = []
> +outputName = None
> +
> +ISO_COPYRIGHT = "Copyright ISO/IEC"
> +COPYRIGHT = "Copyright (C)"
> +GNU_PUBLIC_LICENSE = "GNU General Public License"
> +GNU_LESSER_GENERAL = "GNU Lesser General"
> +GCC_RUNTIME_LIB_EXC = "GCC Runtime Library Exception"
> +VERSION_2_1 = "version 2.1"
> +VERSION_2 = "version 2"
> +VERSION_3 = "version 3"
> +Licenses = {VERSION_2_1: "v2.1", VERSION_2: "v2", VERSION_3: "v3"}
> +CONTRIBUTED_BY = "ontributed by"
> +
> +
> +def printf(fmt, *args):
> +    # printf - keeps C programmers happy :-)
> +    print(str(fmt) % args, end=' ')
> +
> +
> +def error(fmt, *args):
> +    # error - issue an error message.
> +    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]
> +
> +
> +def analyseComment(text, f):
> +    # analyseComment determine the license from the top comment.
> +    start_date, end_date = None, None
> +    contribution, summary, lic = None, None, None
> +    if text.find(ISO_COPYRIGHT) > 0:
> +        lic = "BSISO"
> +        now = datetime.datetime.now()
> +        for d in range(1984, now.year+1):
> +            if text.find(str(d)) > 0:
> +                if start_date is None:
> +                    start_date = str(d)
> +                end_date = str(d)
> +        return start_date, end_date, "", "", lic
> +    elif text.find(COPYRIGHT) > 0:
> +        if text.find(GNU_PUBLIC_LICENSE) > 0:
> +            lic = "GPL"
> +        elif text.find(GNU_LESSER_GENERAL) > 0:
> +            lic = "LGPL"
> +        for license in Licenses.keys():
> +            if text.find(license) > 0:
> +                lic += Licenses[license]
> +        if text.find(GCC_RUNTIME_LIB_EXC) > 0:
> +            lic += "x"
> +        now = datetime.datetime.now()
> +        for d in range(1984, now.year+1):
> +            if text.find(str(d)) > 0:
> +                if start_date is None:
> +                    start_date = str(d)
> +                end_date = str(d)
> +        if text.find(CONTRIBUTED_BY) > 0:
> +            i = text.find(CONTRIBUTED_BY)
> +            i += len(CONTRIBUTED_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
> +
> +
> +def analyseHeaderWithoutTerminator(f, start):
> +    text = ""
> +    for count, l in enumerate(open(f).readlines()):
> +        parts = l.split(start)
> +        if len(parts) > 1:
> +            line = start.join(parts[1:])
> +            line = line.strip()
> +            text += " "
> +            text += line
> +        elif (l.rstrip() != "") and (len(parts[0]) > 0):
> +            return analyseComment(text, f), count
> +    return [None, None, None, None, None], 0
> +
> +
> +def analyseHeaderWithTerminator(f, start, end):
> +    inComment = False
> +    text = ""
> +    for count, line in enumerate(open(f).readlines()):
> +        while line != "":
> +            line = line.strip()
> +            if inComment:
> +                text += " "
> +                pos = line.find(end)
> +                if pos >= 0:
> +                    text += line[:pos]
> +                    line = line[pos:]
> +                    inComment = False
> +                else:
> +                    text += line
> +                    line = ""
> +            else:
> +                pos = line.find(start)
> +                if (pos >= 0) and (len(line) > len(start)):
> +                    before = line[:pos].strip()
> +                    if before != "":
> +                        return analyseComment(text, f), count
> +                    line = line[pos + len(start):]
> +                    inComment = True
> +                elif (line != "") and (line == end):
> +                    line = ""
> +                else:
> +                    return analyseComment(text, f), count
> +    return [None, None, None, None, None], 0
> +
> +
> +def analyseHeader(f, start, end):
> +    # analyseHeader -
> +    if end is None:
> +        return analyseHeaderWithoutTerminator(f, start)
> +    else:
> +        return analyseHeaderWithTerminator(f, start, end)
> +
> +
> +def addStop(sentence):
> +    # addStop - add a full stop to a sentance.
> +    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 = {}
> +templates["GPLv3"] = GPLv3
> +templates["GPLv3x"] = GPLv3x
> +templates["LGPLv3"] = LGPLv3
> +templates["LGPLv2.1"] = LGPLv3
> +templates["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 is not None:
> +                fo.write(magic)
> +                fo.write("\n")
> +            text = templates[lic] % (summary, dates, contribution)
> +            text = text.rstrip()
> +        if end is 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 is 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):
> +    text = "".join(open(f).readlines()[lines:])
> +    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()
> +
> +
> +def handleHeader(f, magic, start, end):
> +    # handleHeader keep reading lines of file, f, looking for start, end
> +    # sequences and comments inside.  The comments are checked for:
> +    # date, contribution, summary
> +    global errorCount
> +
> +    errorCount = 0
> +    [start_date, end_date,
> +     contribution, summary, lic], lines = analyseHeader(f, start, end)
> +    if lic is None:
> +        error("%s:1:no GPL found at the top of the file\n", f)
> +    else:
> +        if args.verbose:
> +            printf("copyright: %s\n", lic)
> +            if (start_date is not None) and (end_date is not None):
> +                if start_date == end_date:
> +                    printf("dates = %s\n", start_date)
> +                else:
> +                    printf("dates = %s-%s\n", start_date, end_date)
> +            if summary is not None:
> +                printf("summary: %s\n", summary)
> +            if contribution is not None:
> +                printf("contribution: %s\n", contribution)
> +        if start_date is None:
> +            error("%s:1:no date found in the GPL at the top of the file\n", f)
> +        if args.contribution is None:
> +            if contribution == "":
> +                error("%s:1:no contribution found in the " +
> +                      "GPL at the top of the file\n", f)
> +            else:
> +                contribution = args.contribution
> +        if summary is None:
> +            if args.summary == "":
> +                error("%s:1:no single line summary found in the " +
> +                      "GPL at the top of the file\n", f)
> +            else:
> +                summary = args.summary
> +    if errorCount == 0:
> +        now = datetime.datetime.now()
> +        if args.no:
> +            print(f, "suppressing change as requested: %s-%s %s"
> +                  % (start_date, end_date, lic))
> +        else:
> +            if lic == "BSISO":
> +                # don't change the BS ISO license!
> +                pass
> +            elif args.extensions:
> +                lic = "GPLv3x"
> +            elif args.gpl3:
> +                lic = "GPLv3"
> +            rewriteFile(f, magic, start, end, start_date,
> +                        str(now.year), contribution, summary, lic, lines)
> +    else:
> +        printf("too many errors, no modifications will occur\n")
> +
> +
> +def bashTidy(f):
> +    # bashTidy tidy up dates using '#' comment
> +    handleHeader(f, "#!/bin/bash", "#", None)
> +
> +
> +def pythonTidy(f):
> +    # pythonTidy tidy up dates using '#' comment
> +    handleHeader(f, "#!/usr/bin/env python3", '#', None)
> +
> +
> +def bnfTidy(f):
> +    # bnfTidy tidy up dates using '--' comment
> +    handleHeader(f, None, '--', None)
> +
> +
> +def cTidy(f):
> +    # cTidy tidy up dates using '/* */' comments
> +    handleHeader(f, None, '/*', '*/')
> +
> +
> +def m2Tidy(f):
> +    # m2Tidy tidy up dates using '(* *)' comments
> +    handleHeader(f, None, '(*', '*)')
> +
> +
> +def inTidy(f):
> +    # inTidy tidy up dates using '#' as a comment and check
> +    # the first line for magic number.
> +    first = open(f).readlines()[0]
> +    if (len(first) > 0) and (first[:2] == "#!"):
> +        # magic number found, use this
> +        handleHeader(f, first, "#", None)
> +    else:
> +        handleHeader(f, None, "#", None)
> +
> +
> +def doVisit(args, dirname, names):
> +    # doVisit helper function to call func on every extension file.
> +    global outputName
> +    func, extension = args
> +    for f in names:
> +        if len(f) > len(extension) and f[-len(extension):] == extension:
> +            outputName = f
> +            func(os.path.join(dirname, f))
> +
> +
> +def visitDir(startDir, ext, func):
> +    # visitDir call func for each file in startDir which has ext.
> +    global outputName, seenFiles
> +    for dirName, subdirList, fileList in os.walk(startDir):
> +        for fname in fileList:
> +            if (len(fname) > len(ext)) and (fname[-len(ext):] == ext):
> +                fullpath = os.path.join(dirName, fname)
> +                outputName = fullpath
> +                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]
> +
> +
> +def findFiles():
> +    # findFiles for each file extension call the appropriate tidy routine.
> +    visitDir(args.recursive, '.h.in', cTidy)
> +    visitDir(args.recursive, '.in', inTidy)
> +    visitDir(args.recursive, '.sh', inTidy)
> +    visitDir(args.recursive, '.py', pythonTidy)
> +    visitDir(args.recursive, '.c', cTidy)
> +    visitDir(args.recursive, '.h', cTidy)
> +    visitDir(args.recursive, '.cc', cTidy)
> +    visitDir(args.recursive, '.def', m2Tidy)
> +    visitDir(args.recursive, '.mod', m2Tidy)
> +    visitDir(args.recursive, '.bnf', bnfTidy)
> +
> +
> +def handleArguments():
> +    # handleArguments create and return the args object.
> +    parser = argparse.ArgumentParser()
> +    parser.add_argument("-c", "--contribution",
> +                        help="set the contribution string " +
> +                        "at the top of the file.",
> +                        default="", action="store")
> +    parser.add_argument("-d", "--debug", help="turn on internal debugging.",
> +                        default=False, action="store_true")
> +    parser.add_argument("-f", "--force",
> +                        help="force a check to insist that the " +
> +                        "contribution, summary and GPL exist.",
> +                        default=False, action="store_true")
> +    parser.add_argument("-g", "--gplv3", help="change to GPLv3",
> +                        default=False, action="store_true")
> +    parser.add_argument("-o", "--outputfile", help="set the output file",
> +                        default="-", action="store")
> +    parser.add_argument("-r", "--recursive",
> +                        help="recusively scan directory for known file " +
> +                        "extensions (.def, .mod, .c, .h, .py, .in, .sh).",
> +                        default=".", action="store")
> +    parser.add_argument("-s", "--summary",
> +                        help="set the summary line for the file.",
> +                        default=None, action="store")
> +    parser.add_argument("-u", "--update", help="update all dates.",
> +                        default=False, action="store_true")
> +    parser.add_argument("-v", "--verbose",
> +                        help="display copyright, " +
> +                        "date and contribution messages",
> +                        action="store_true")
> +    parser.add_argument("-x", "--extensions",
> +                        help="change to GPLv3 with GCC runtime extensions.",
> +                        default=False, action="store_true")
> +    parser.add_argument("-N", "--no",
> +                        help="do not modify any file.",
> +                        action="store_true")
> +    args = parser.parse_args()
> +    return args
> +
> +
> +def hasExt(name, ext):
> +    # hasExt return True if, name, ends with, ext.
> +    if len(name) > len(ext):
> +        return name[-len(ext):] == ext
> +    return False
> +
> +
> +def singleFile(name):
> +    # singleFile scan the single file for a GPL boilerplate which
> +    # has a GPL, contribution field and a summary heading.
> +    if hasExt(name, ".def") or hasExt(name, ".mod"):
> +        m2Tidy(name)
> +    elif hasExt(name, ".h") or hasExt(name, ".c") or hasExt(name, ".cc"):
> +        cTidy(name)
> +    elif hasExt(name, ".in"):
> +        inTidy(name)
> +    elif hasExt(name, ".sh"):
> +        inTidy(name)  # uses magic number for actual sh/bash
> +    elif hasExt(name, ".py"):
> +        pythonTidy(name)
> +
> +
> +def main():
> +    # main - handleArguments and then find source files.
> +    global args, outputName
> +    args = handleArguments()
> +    outputName = args.outputfile
> +    if args.recursive:
> +        findFiles()
> +    elif args.inputfile is None:
> +        print("an input file must be specified on the command line")
> +    else:
> +        singleFile(args.inputfile)
> +    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-11-05 17:33:53.685584357 +0000
> @@ -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-11-05 17:33:53.685584357 +0000
> @@ -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-11-05 17:33:53.685584357 +0000
> @@ -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-11-05 17:33:53.685584357 +0000
> @@ -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/def2doc.py
> --- /dev/null	2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/tools-src/def2doc.py	2022-11-05 17:33:53.685584357 +0000
> @@ -0,0 +1,419 @@
> +#!/usr/bin/env python3
> +
> +# def2doc.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 argparse
> +import os
> +import sys
> +
> +BaseLibs = ["gm2-libs", "Base libraries", "Basic M2F compatible libraries"]
> +
> +PIMLogDesc = "PIM and Logitech 3.0 compatible libraries"
> +PIMLog = ["gm2-libs-pim", "PIM and Logitech 3.0 Compatible", PIMLogDesc]
> +PIMCorDesc = "PIM compatible process support"
> +PIMCor = ["gm2-libs-coroutines", "PIM coroutine support", PIMCorDesc]
> +ISOLibs = ["gm2-libs-iso", "M2 ISO Libraries", "ISO defined libraries"]
> +
> +libraryClassifications = [BaseLibs, PIMLog, PIMCor, ISOLibs]
> +
> +
> +def initState():
> +    global inVar, inType, inConst
> +    inVar, inType, inConst = False, False, False
> +
> +
> +def emitNode(name, nxt, previous, up):
> +    if args.texinfo:
> +        output.write("@node " + name + ", " + nxt + ", ")
> +        output.write(previous + ", " + up + "\n")
> +    elif args.sphinx:
> +        output.write("@c @node " + name + ", " + nxt + ", ")
> +        output.write(previous + ", " + up + "\n")
> +
> +
> +def emitSection(name):
> +    if args.texinfo:
> +        output.write("@section " + name + "\n")
> +    elif args.sphinx:
> +        output.write(name + "\n")
> +        output.write("=" * len(name) + "\n")
> +
> +
> +def emitSubSection(name):
> +    if args.texinfo:
> +        output.write("@subsection " + name + "\n")
> +    elif args.sphinx:
> +        output.write(name + "\n")
> +        output.write("-" * len(name) + "\n")
> +
> +
> +def displayLibraryClass():
> +    # displayLibraryClass displays a node for a library directory and invokes
> +    # a routine to summarize each module.
> +    global args
> +    previous = ""
> +    nxt = libraryClassifications[1][1]
> +    i = 0
> +    lib = libraryClassifications[i]
> +    while True:
> +        emitNode(lib[1], nxt, previous, args.up)
> +        emitSection(lib[1])
> +        output.write("\n")
> +        displayModules(lib[1], lib[0], args.builddir, args.sourcedir)
> +        output.write("\n")
> +        output.write("@c " + "-" * 60 + "\n")
> +        previous = lib[1]
> +        i += 1
> +        if i == len(libraryClassifications):
> +            break
> +        lib = libraryClassifications[i]
> +        if i+1 == len(libraryClassifications):
> +            nxt = ""
> +        else:
> +            nxt = libraryClassifications[i+1][1]
> +
> +
> +def displayMenu():
> +    # displayMenu displays the top level menu for library documentation.
> +    output.write("@menu\n")
> +    for lib in libraryClassifications:
> +        output.write("* " + lib[1] + "::" + lib[2] + "\n")
> +    output.write("@end menu\n")
> +    output.write("\n")
> +    output.write("@c " + "=" * 60 + "\n")
> +    output.write("\n")
> +
> +
> +def removeInitialComments(file, line):
> +    # removeInitialComments removes any (* *) at the top
> +    # of the definition module.
> +    while (str.find(line, "*)") == -1):
> +        line = file.readline()
> +
> +
> +def removeableField(line):
> +    # removeableField - returns True if a comment field should be removed
> +    # from the definition module.
> +    field_list = ["Author", "Last edit", "LastEdit", "Last update",
> +                  "Date", "Title", "Revision"]
> +    for field in field_list:
> +        if (str.find(line, field) != -1) and (str.find(line, ":") != -1):
> +            return True
> +    ignore_list = ["System", "SYSTEM"]
> +    for ignore_field in ignore_list:
> +        if str.find(line, ignore_field) != -1:
> +            if str.find(line, ":") != -1:
> +                if str.find(line, "Description:") == -1:
> +                    return True
> +    return False
> +
> +
> +def removeFields(file, line):
> +    # removeFields removes Author/Date/Last edit/SYSTEM/Revision
> +    # fields from a comment within the start of a definition module.
> +    while (str.find(line, "*)") == -1):
> +        if not removeableField(line):
> +            output.write(str.replace(str.replace(str.rstrip(line),
> +                                                 "{", "@{"), "}", "@}") + "\n")
> +        line = file.readline()
> +    output.write(str.rstrip(line) + "\n")
> +
> +
> +def checkIndex(line):
> +    # checkIndex - create an index entry for a PROCEDURE, TYPE, CONST or VAR.
> +    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:
> +                    output.write("@findex " + word + " (var)\n")
> +                elif len(word) > 0:
> +                    var = str.split(word, ":")
> +                    if len(var) > 0:
> +                        output.write("@findex " + var[0] + " (var)\n")
> +
> +    if inType:
> +        words = str.lstrip(line)
> +        if str.find(words, "=") != -1:
> +            word = str.split(words, "=")
> +            if (len(word[0]) > 0) and (word[0][0] != "_"):
> +                output.write("@findex " + str.rstrip(word[0]) + " (type)\n")
> +        else:
> +            word = str.split(words)
> +            if (len(word) > 1) and (word[1] == ";"):
> +                # hidden type
> +                if (len(word[0]) > 0) and (word[0][0] != "_"):
> +                    output.write("@findex " + str.rstrip(word[0]))
> +                    output.write(" (type)\n")
> +    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:
> +                        output.write("@findex " + var[0] + " (const)\n")
> +    if procedure != "":
> +        name = str.split(procedure, "(")
> +        if name[0] != "":
> +            proc = name[0]
> +            if proc[-1] == ";":
> +                proc = proc[:-1]
> +            if proc != "":
> +                output.write("@findex " + proc + "\n")
> +
> +
> +def parseDefinition(dir, source, build, file, needPage):
> +    # parseDefinition reads a definition module and creates
> +    # indices for procedures, constants, variables and types.
> +    output.write("\n")
> +    with open(findFile(dir, build, source, file), "r") as f:
> +        initState()
> +        line = f.readline()
> +        while (str.find(line, "(*") != -1):
> +            removeInitialComments(f, line)
> +            line = f.readline()
> +        while (str.find(line, "DEFINITION") == -1):
> +            line = f.readline()
> +        output.write("@example\n")
> +        output.write(str.rstrip(line) + "\n")
> +        line = f.readline()
> +        if len(str.rstrip(line)) == 0:
> +            output.write("\n")
> +            line = f.readline()
> +            if (str.find(line, "(*") != -1):
> +                removeFields(f, line)
> +            else:
> +                output.write(str.rstrip(line) + "\n")
> +        else:
> +            output.write(str.rstrip(line) + "\n")
> +        line = f.readline()
> +        while line:
> +            line = str.rstrip(line)
> +            checkIndex(line)
> +            output.write(str.replace(str.replace(line, "{", "@{"), "}", "@}"))
> +            output.write("\n")
> +            line = f.readline()
> +        output.write("@end example\n")
> +        if needPage:
> +            output.write("@page\n")
> +
> +
> +def parseModules(up, dir, build, source, listOfModules):
> +    previous = ""
> +    i = 0
> +    if len(listOfModules) > 1:
> +        nxt = dir + "/" + listOfModules[1][:-4]
> +    else:
> +        nxt = ""
> +    while i < len(listOfModules):
> +        emitNode(dir + "/" + listOfModules[i][:-4], nxt, previous, up)
> +        emitSubSection(dir + "/" + listOfModules[i][:-4])
> +        parseDefinition(dir, source, build, listOfModules[i], True)
> +        output.write("\n")
> +        previous = dir + "/" + listOfModules[i][:-4]
> +        i = i + 1
> +        if i+1 < len(listOfModules):
> +            nxt = dir + "/" + listOfModules[i+1][:-4]
> +        else:
> +            nxt = ""
> +
> +
> +def doCat(name):
> +    # doCat displays the contents of file, name, to stdout
> +    with open(name, "r") as file:
> +        line = file.readline()
> +        while line:
> +            output.write(str.rstrip(line) + "\n")
> +            line = file.readline()
> +
> +
> +def moduleMenu(dir, build, source):
> +    # moduleMenu generates a simple menu for all definition modules
> +    # in dir
> +    output.write("@menu\n")
> +    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"):
> +                output.write("* " + dir + "/" + file[:-4] + "::" + file + "\n")
> +    output.write("@end menu\n")
> +    output.write("\n")
> +
> +
> +def checkDirectory(dir, build, source):
> +    # checkDirectory - returns True if dir exists in either build or 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
> +
> +
> +def foundFile(dir, build, source, file):
> +    # foundFile return True if file is found in build/dir/file or
> +    # source/dir/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
> +
> +
> +def findFile(dir, build, source, file):
> +    # findFile return the path to file searching in build/dir/file
> +    # first then source/dir/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
> +    sys.stderr.write("file cannot be found in either " + name1)
> +    sys.stderr.write(" or " + name2 + "\n")
> +    os.sys.exit(1)
> +
> +
> +def displayModules(up, dir, build, source):
> +    # displayModules walks though the files in dir and parses
> +    # definition modules and includes README.texi
> +    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:
> +        line = "directory " + dir + " not found in either "
> +        line += build + " or " + source
> +        sys.stderr.write(line + "\n")
> +
> +
> +def displayCopyright():
> +    output.write("@c Copyright (C) 2000-2022 Free Software Foundation, Inc.\n")
> +    output.write("@c This file is part of GNU Modula-2.\n")
> +    output.write("""
> +@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 collectArgs():
> +    parser = argparse.ArgumentParser()
> +    parser.add_argument("-v", "--verbose", help="generate progress messages",
> +                        action="store_true")
> +    parser.add_argument("-b", "--builddir", help="set the build directory",
> +                        default=".", action="store")
> +    parser.add_argument("-f", "--inputfile", help="set the input file",
> +                        default=None, action="store")
> +    parser.add_argument("-o", "--outputfile", help="set the output file",
> +                        default=None, action="store")
> +    parser.add_argument("-s", "--sourcedir", help="set the source directory",
> +                        default=".", action="store")
> +    parser.add_argument("-t", "--texinfo",
> +                        help="generate texinfo documentation",
> +                        default=False, action="store_true")
> +    parser.add_argument("-u", "--up", help="set the up node",
> +                        default="", action="store")
> +    parser.add_argument("-x", "--sphinx", help="generate sphinx documentation",
> +                        default=False, action="store_true")
> +    args = parser.parse_args()
> +    return args
> +
> +
> +def handleFile():
> +    if args.inputfile is None:
> +        displayCopyright()
> +        displayMenu()
> +        displayLibraryClass()
> +    else:
> +        parseDefinition(".", args.sourcedir, args.builddir,
> +                        args.inputfile, False)
> +
> +
> +def main():
> +    global args, output
> +    args = collectArgs()
> +    if args.outputfile is None:
> +        output = sys.stdout
> +        handleFile()
> +    else:
> +        with open(args.outputfile, "w") as output:
> +            handleFile()
> +
> +
> +main()
> 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-11-07 13:01:28.329424600 +0000
> @@ -0,0 +1,807 @@
> +/* 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 ((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");
> +    }
> +}


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-07 13:47       ` Martin Liška
@ 2022-11-08 13:22         ` Gaius Mulley
  2022-11-24 11:53           ` Martin Liška
  0 siblings, 1 reply; 13+ messages in thread
From: Gaius Mulley @ 2022-11-08 13:22 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches

Martin Liška <mliska@suse.cz> writes:

> 1) I would prefer using ' instead of ":
>
> $ flake8 ./gcc/m2/tools-src/tidydates.py
> ...
> ./gcc/m2/tools-src/tidydates.py:124:30: Q000 Double quotes found but single quotes preferred
> ./gcc/m2/tools-src/tidydates.py:127:27: Q000 Double quotes found but single quotes preferred
> ./gcc/m2/tools-src/tidydates.py:132:27: Q000 Double quotes found but single quotes preferred
> ./gcc/m2/tools-src/tidydates.py:133:33: Q000 Double quotes found but single quotes preferred
> ./gcc/m2/tools-src/tidydates.py:138:26: Q000 Double quotes found but single quotes preferred
> ./gcc/m2/tools-src/tidydates.py:143:28: Q000 Double quotes found but
> single quotes preferred

ah yes will switch the quotes character.

> 2) Python-names would be nicer:
>
> def writeTemplate(fo, magic, start, end, dates, contribution, summary,
> lic):
>
> def write_template(...)

agreed, will change

> 3) def hasExt(name, ext) - please use Path from pathlib
>
> 4)         while (str.find(line, "(*") != -1):
>
> '(*' in line
> ? Similarly elsewhere.
>
> 5) str.find(line, ...)
>
> Use rather directly: line.find(...)
>
> 6) please use flake8:
> https://gcc.gnu.org/codingconventions.html#python

sure will do all above - I used flake8 but maybe the plugins weren't
enabled.  I'll try flake8 on tumbleweed.

> Thanks,
> Martin
>
> P.S. I'm going to merge Sphinx branch this Wednesday, so then we should port your
> conversion scripts to emit .rst instead of .texi.

should be good - I'll complete the rst output in the scripts,

regards,
Gaius

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-08 13:22         ` Gaius Mulley
@ 2022-11-24 11:53           ` Martin Liška
  2022-11-24 14:30             ` Gaius Mulley
  0 siblings, 1 reply; 13+ messages in thread
From: Martin Liška @ 2022-11-24 11:53 UTC (permalink / raw)
  To: Gaius Mulley; +Cc: gcc-patches

On 11/8/22 14:22, Gaius Mulley wrote:
> Martin Liška <mliska@suse.cz> writes:
> 
>> 1) I would prefer using ' instead of ":
>>
>> $ flake8 ./gcc/m2/tools-src/tidydates.py
>> ...
>> ./gcc/m2/tools-src/tidydates.py:124:30: Q000 Double quotes found but single quotes preferred
>> ./gcc/m2/tools-src/tidydates.py:127:27: Q000 Double quotes found but single quotes preferred
>> ./gcc/m2/tools-src/tidydates.py:132:27: Q000 Double quotes found but single quotes preferred
>> ./gcc/m2/tools-src/tidydates.py:133:33: Q000 Double quotes found but single quotes preferred
>> ./gcc/m2/tools-src/tidydates.py:138:26: Q000 Double quotes found but single quotes preferred
>> ./gcc/m2/tools-src/tidydates.py:143:28: Q000 Double quotes found but
>> single quotes preferred
> 
> ah yes will switch the quotes character.
> 
>> 2) Python-names would be nicer:
>>
>> def writeTemplate(fo, magic, start, end, dates, contribution, summary,
>> lic):
>>
>> def write_template(...)
> 
> agreed, will change
> 
>> 3) def hasExt(name, ext) - please use Path from pathlib
>>
>> 4)         while (str.find(line, "(*") != -1):
>>
>> '(*' in line
>> ? Similarly elsewhere.
>>
>> 5) str.find(line, ...)
>>
>> Use rather directly: line.find(...)
>>
>> 6) please use flake8:
>> https://gcc.gnu.org/codingconventions.html#python
> 
> sure will do all above - I used flake8 but maybe the plugins weren't
> enabled.  I'll try flake8 on tumbleweed.
> 
>> Thanks,
>> Martin
>>
>> P.S. I'm going to merge Sphinx branch this Wednesday, so then we should port your
>> conversion scripts to emit .rst instead of .texi.
> 
> should be good - I'll complete the rst output in the scripts,
> 
> regards,
> Gaius

Hi.

As you probably noticed, the Sphinx migration didn't go well. However, it's still up to you
if you want to use it or not for Modula 2. We have manuals like libgccjit, or Ada manuals
that use RST natively and provide exported .texi files.

Cheers and sorry for the troubles I caused.

Martin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-24 11:53           ` Martin Liška
@ 2022-11-24 14:30             ` Gaius Mulley
  2022-11-25 16:25               ` Martin Liška
  2022-11-25 17:10               ` David Malcolm
  0 siblings, 2 replies; 13+ messages in thread
From: Gaius Mulley @ 2022-11-24 14:30 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches

Martin Liška <mliska@suse.cz> writes:

> On 11/8/22 14:22, Gaius Mulley wrote:
>> Martin Liška <mliska@suse.cz> writes:
>> 
>> should be good - I'll complete the rst output in the scripts,
>
> Hi.
>

Hi Martin,

> As you probably noticed, the Sphinx migration didn't go well.

Yes, sorry to see this didn't happen.  Thank you for your hard work and
I hope it can occur in the future.

> However, it's still up to you if you want to use it or not for Modula
> 2.

Once modula-2 is in master I'd like to revisit rst in devel/modula-2
along with analyzer patches and m2 generics.  If successful then submit
patches in early stage 1.

> We have manuals like libgccjit, or Ada manuals
> that use RST natively and provide exported .texi files.

Ok thanks for the pointers, I will experiment with these build rhunes.

> Cheers and sorry for the troubles I caused.

No problem at all - the modula-2 scripts are now improved and cleaner
due to the port.  Hopefully rst will happen sometime in the future,

regards,
Gaius

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-24 14:30             ` Gaius Mulley
@ 2022-11-25 16:25               ` Martin Liška
  2022-11-25 17:10               ` David Malcolm
  1 sibling, 0 replies; 13+ messages in thread
From: Martin Liška @ 2022-11-25 16:25 UTC (permalink / raw)
  To: Gaius Mulley; +Cc: gcc-patches

On 11/24/22 15:30, Gaius Mulley wrote:
> Martin Liška <mliska@suse.cz> writes:
> 
>> On 11/8/22 14:22, Gaius Mulley wrote:
>>> Martin Liška <mliska@suse.cz> writes:
>>>
>>> should be good - I'll complete the rst output in the scripts,
>>
>> Hi.
>>
> 
> Hi Martin,
> 
>> As you probably noticed, the Sphinx migration didn't go well.
> 
> Yes, sorry to see this didn't happen.  Thank you for your hard work and
> I hope it can occur in the future.

Hi.

We'll see, it's not in my plans for near future.

> 
>> However, it's still up to you if you want to use it or not for Modula
>> 2.
> 
> Once modula-2 is in master I'd like to revisit rst in devel/modula-2
> along with analyzer patches and m2 generics.  If successful then submit
> patches in early stage 1.

Sounds good.

> 
>> We have manuals like libgccjit, or Ada manuals
>> that use RST natively and provide exported .texi files.
> 
> Ok thanks for the pointers, I will experiment with these build rhunes.
> 
>> Cheers and sorry for the troubles I caused.
> 
> No problem at all - the modula-2 scripts are now improved and cleaner
> due to the port.  Hopefully rst will happen sometime in the future,

Regards,
Martin

> 
> regards,
> Gaius


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-24 14:30             ` Gaius Mulley
  2022-11-25 16:25               ` Martin Liška
@ 2022-11-25 17:10               ` David Malcolm
  2022-11-27 16:51                 ` Gaius Mulley
  1 sibling, 1 reply; 13+ messages in thread
From: David Malcolm @ 2022-11-25 17:10 UTC (permalink / raw)
  To: Gaius Mulley, Martin Liška; +Cc: gcc-patches

On Thu, 2022-11-24 at 14:30 +0000, Gaius Mulley via Gcc-patches wrote:
> Martin Liška <mliska@suse.cz> writes:
> 
> > On 11/8/22 14:22, Gaius Mulley wrote:
> > > Martin Liška <mliska@suse.cz> writes:
> > > 
> > > should be good - I'll complete the rst output in the scripts,
> > 
> > Hi.
> > 
> 
> Hi Martin,
> 
> > As you probably noticed, the Sphinx migration didn't go well.
> 
> Yes, sorry to see this didn't happen.  Thank you for your hard work
> and
> I hope it can occur in the future.

Likewise, thanks for all your work on this.

> 
> > However, it's still up to you if you want to use it or not for
> > Modula
> > 2.
> 
> Once modula-2 is in master I'd like to revisit rst in devel/modula-2
> along with analyzer patches and m2 generics.  If successful then
> submit
> patches in early stage 1.

Am I right in thinking the analyzer stuff would be an updated version
of the work you posted here:
 https://gcc.gnu.org/pipermail/gcc-patches/2021-April/567953.html
?

Thanks
Dave


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 16/19] modula2 front end: bootstrap and documentation tools
  2022-11-25 17:10               ` David Malcolm
@ 2022-11-27 16:51                 ` Gaius Mulley
  0 siblings, 0 replies; 13+ messages in thread
From: Gaius Mulley @ 2022-11-27 16:51 UTC (permalink / raw)
  To: David Malcolm; +Cc: Martin Liška, gcc-patches

David Malcolm <dmalcolm@redhat.com> writes:

>> Once modula-2 is in master I'd like to revisit rst in devel/modula-2
>> along with analyzer patches and m2 generics.  If successful then
>> submit
>> patches in early stage 1.
>
> Am I right in thinking the analyzer stuff would be an updated version
> of the work you posted here:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-April/567953.html ?

Sure, yes.

regards,
Gaius

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-11-27 16:52 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-10 15:31 [PATCH] 16/19 modula2 front end: bootstrap and documentation tools Gaius Mulley
2022-10-13  9:12 ` Martin Liška
2022-10-14 12:10   ` Gaius Mulley
2022-11-07 13:09     ` [PATCH v2 16/19] " Gaius Mulley
2022-11-07 13:47       ` Martin Liška
2022-11-08 13:22         ` Gaius Mulley
2022-11-24 11:53           ` Martin Liška
2022-11-24 14:30             ` Gaius Mulley
2022-11-25 16:25               ` Martin Liška
2022-11-25 17:10               ` David Malcolm
2022-11-27 16:51                 ` Gaius Mulley
2022-10-20 12:42 ` [PATCH] 16/19 " Martin Liška
2022-10-28 13:05   ` Gaius Mulley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).