aboutsummaryrefslogtreecommitdiff
path: root/gcc/m2/tools-src
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/m2/tools-src')
-rw-r--r--gcc/m2/tools-src/README3
-rw-r--r--gcc/m2/tools-src/boilerplate.py548
-rw-r--r--gcc/m2/tools-src/buildpg289
-rwxr-xr-xgcc/m2/tools-src/calcpath51
-rw-r--r--gcc/m2/tools-src/def2doc.py539
-rw-r--r--gcc/m2/tools-src/makeSystem108
-rw-r--r--gcc/m2/tools-src/mklink.c807
-rw-r--r--gcc/m2/tools-src/tidydates.py166
8 files changed, 2511 insertions, 0 deletions
diff --git a/gcc/m2/tools-src/README b/gcc/m2/tools-src/README
new file mode 100644
index 0000000..e2e0dce
--- /dev/null
+++ b/gcc/m2/tools-src/README
@@ -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 --git a/gcc/m2/tools-src/boilerplate.py b/gcc/m2/tools-src/boilerplate.py
new file mode 100644
index 0000000..9959652
--- /dev/null
+++ b/gcc/m2/tools-src/boilerplate.py
@@ -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
+
+
+error_count = 0
+seen_files = []
+output_name = 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 error_count
+
+ print(str(fmt) % args, end=' ')
+ error_count += 1
+
+
+def halt_on_error():
+ if error_count > 0:
+ os.sys.exit(1)
+
+
+def basename(f):
+ b = f.split('/')
+ return b[-1]
+
+
+def analyse_comment(text, f):
+ # analyse_comment 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 analyse_header_without_terminator(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 analyse_comment(text, f), count
+ return [None, None, None, None, None], 0
+
+
+def analyse_header_with_terminator(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 analyse_comment(text, f), count
+ line = line[pos + len(start):]
+ inComment = True
+ elif (line != '') and (line == end):
+ line = ''
+ else:
+ return analyse_comment(text, f), count
+ return [None, None, None, None, None], 0
+
+
+def analyse_header(f, start, end):
+ # analyse_header -
+ if end is None:
+ return analyse_header_without_terminator(f, start)
+ else:
+ return analyse_header_with_terminator(f, start, end)
+
+
+def add_stop(sentence):
+ # add_stop - 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 write_template(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 = add_stop(summary)
+ contribution = add_stop(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 write_boiler_plate(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 write_template(fo, magic, start, end,
+ dates, contribution, summary, gpl)
+
+
+def rewrite_file(f, magic, start, end, start_date, end_date,
+ contribution, summary, gpl, lines):
+ text = ''.join(open(f).readlines()[lines:])
+ if output_name == '-':
+ fo = sys.stdout
+ else:
+ fo = open(f, 'w')
+ fo = write_boiler_plate(fo, magic, start, end,
+ start_date, end_date, contribution, summary, gpl)
+ fo.write(text)
+ fo.flush()
+ if output_name != '-':
+ fo.close()
+
+
+def handle_header(f, magic, start, end):
+ # handle_header keep reading lines of file, f, looking for start, end
+ # sequences and comments inside. The comments are checked for:
+ # date, contribution, summary
+ global error_count
+
+ error_count = 0
+ [start_date, end_date,
+ contribution, summary, lic], lines = analyse_header(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 error_count == 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'
+ rewrite_file(f, magic, start, end, start_date,
+ str(now.year), contribution, summary, lic, lines)
+ else:
+ printf('too many errors, no modifications will occur\n')
+
+
+def bash_tidy(f):
+ # bash_tidy tidy up dates using '#' comment
+ handle_header(f, '#!/bin/bash', '#', None)
+
+
+def python_tidy(f):
+ # python_tidy tidy up dates using '#' comment
+ handle_header(f, '#!/usr/bin/env python3', '#', None)
+
+
+def bnf_tidy(f):
+ # bnf_tidy tidy up dates using '--' comment
+ handle_header(f, None, '--', None)
+
+
+def c_tidy(f):
+ # c_tidy tidy up dates using '/* */' comments
+ handle_header(f, None, '/*', '*/')
+
+
+def m2_tidy(f):
+ # m2_tidy tidy up dates using '(* *)' comments
+ handle_header(f, None, '(*', '*)')
+
+
+def in_tidy(f):
+ # in_tidy 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
+ handle_header(f, first, '#', None)
+ else:
+ handle_header(f, None, '#', None)
+
+
+def do_visit(args, dirname, names):
+ # do_visit helper function to call func on every extension file.
+ global output_name
+ func, extension = args
+ for f in names:
+ if len(f) > len(extension) and f[-len(extension):] == extension:
+ output_name = f
+ func(os.path.join(dirname, f))
+
+
+def visit_dir(startDir, ext, func):
+ # visit_dir call func for each file in startDir which has ext.
+ global output_name, seen_files
+ 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)
+ output_name = fullpath
+ if not (fullpath in seen_files):
+ seen_files += [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 find_files():
+ # find_files for each file extension call the appropriate tidy routine.
+ visit_dir(args.recursive, '.h.in', c_tidy)
+ visit_dir(args.recursive, '.in', in_tidy)
+ visit_dir(args.recursive, '.sh', in_tidy)
+ visit_dir(args.recursive, '.py', python_tidy)
+ visit_dir(args.recursive, '.c', c_tidy)
+ visit_dir(args.recursive, '.h', c_tidy)
+ visit_dir(args.recursive, '.cc', c_tidy)
+ visit_dir(args.recursive, '.def', m2_tidy)
+ visit_dir(args.recursive, '.mod', m2_tidy)
+ visit_dir(args.recursive, '.bnf', bnf_tidy)
+
+
+def handle_arguments():
+ # handle_arguments 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 has_ext(name, ext):
+ # has_ext return True if, name, ends with, ext.
+ if len(name) > len(ext):
+ return name[-len(ext):] == ext
+ return False
+
+
+def single_file(name):
+ # single_file scan the single file for a GPL boilerplate which
+ # has a GPL, contribution field and a summary heading.
+ if has_ext(name, '.def') or has_ext(name, '.mod'):
+ m2_tidy(name)
+ elif has_ext(name, '.h') or has_ext(name, '.c') or has_ext(name, '.cc'):
+ c_tidy(name)
+ elif has_ext(name, '.in'):
+ in_tidy(name)
+ elif has_ext(name, '.sh'):
+ in_tidy(name) # uses magic number for actual sh/bash
+ elif has_ext(name, '.py'):
+ python_tidy(name)
+
+
+def main():
+ # main - handle_arguments and then find source files.
+ global args, output_name
+ args = handle_arguments()
+ output_name = args.outputfile
+ if args.recursive:
+ find_files()
+ elif args.inputfile is None:
+ print('an input file must be specified on the command line')
+ else:
+ single_file(args.inputfile)
+ halt_on_error()
+
+
+main()
diff --git a/gcc/m2/tools-src/buildpg b/gcc/m2/tools-src/buildpg
new file mode 100644
index 0000000..dce5d4c
--- /dev/null
+++ b/gcc/m2/tools-src/buildpg
@@ -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 --git a/gcc/m2/tools-src/calcpath b/gcc/m2/tools-src/calcpath
new file mode 100755
index 0000000..e081770
--- /dev/null
+++ b/gcc/m2/tools-src/calcpath
@@ -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 --git a/gcc/m2/tools-src/def2doc.py b/gcc/m2/tools-src/def2doc.py
new file mode 100644
index 0000000..d1637ee
--- /dev/null
+++ b/gcc/m2/tools-src/def2doc.py
@@ -0,0 +1,539 @@
+#!/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
+
+Base_Libs = ['gm2-libs', 'Base libraries', 'Basic M2F compatible libraries']
+
+PIM_Log_Desc = 'PIM and Logitech 3.0 compatible libraries'
+PIM_Log = ['gm2-libs-pim', 'PIM and Logitech 3.0 Compatible', PIM_Log_Desc]
+PIM_Cor_Desc = 'PIM compatible process support'
+PIM_Cor = ['gm2-libs-coroutines', 'PIM coroutine support', PIM_Cor_Desc]
+ISO_Libs = ['gm2-libs-iso', 'M2 ISO Libraries', 'ISO defined libraries']
+
+library_classifications = [Base_Libs, PIM_Log, PIM_Cor, ISO_Libs]
+
+# state_states
+state_none, state_var, state_type, state_const = range(4)
+# block states
+block_none, block_code, block_text, block_index = range(4)
+
+
+class state:
+ def __init__(self):
+ self._state_state = state_none
+ self._block = block_none
+
+ def get_state(self):
+ return self._state_state
+
+ def set_state(self, value):
+ self._state_state = value
+
+ def is_const(self):
+ return self._state_state == state_const
+
+ def is_type(self):
+ return self._state_state == state_type
+
+ def is_var(self):
+ return self._state_state == state_var
+
+ def get_block(self):
+ return self._block
+
+ def _change_block(self, new_block):
+ if self._block != new_block:
+ self._block = new_block
+ self._emit_block_desc()
+
+ def _emit_block_desc(self):
+ if self._block == block_code:
+ output.write('.. code-block:: modula2\n')
+ elif self._block == block_index:
+ output.write('.. index::\n')
+
+ def to_code(self):
+ self._change_block(block_code)
+
+ def to_index(self):
+ self._change_block(block_index)
+
+
+def init_state():
+ global state_obj
+ state_obj = state()
+
+
+def emit_node(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 emit_section(name):
+ if args.texinfo:
+ output.write('@section ' + name + '\n')
+ elif args.sphinx:
+ output.write(name + '\n')
+ output.write('=' * len(name) + '\n')
+
+
+def emit_sub_section(name):
+ if args.texinfo:
+ output.write('@subsection ' + name + '\n')
+ elif args.sphinx:
+ output.write(name + '\n')
+ output.write('-' * len(name) + '\n')
+
+
+def display_library_class():
+ # display_library_class displays a node for a library directory and invokes
+ # a routine to summarize each module.
+ global args
+ previous = ''
+ nxt = library_classifications[1][1]
+ i = 0
+ lib = library_classifications[i]
+ while True:
+ emit_node(lib[1], nxt, previous, args.up)
+ emit_section(lib[1])
+ output.write('\n')
+ display_modules(lib[1], lib[0], args.builddir, args.sourcedir)
+ output.write('\n')
+ output.write('@c ' + '-' * 60 + '\n')
+ previous = lib[1]
+ i += 1
+ if i == len(library_classifications):
+ break
+ lib = library_classifications[i]
+ if i+1 == len(library_classifications):
+ nxt = ''
+ else:
+ nxt = library_classifications[i+1][1]
+
+
+def display_menu():
+ # display_menu displays the top level menu for library documentation.
+ output.write('@menu\n')
+ for lib in library_classifications:
+ output.write('* ' + lib[1] + '::' + lib[2] + '\n')
+ output.write('@end menu\n')
+ output.write('\n')
+ output.write('@c ' + '=' * 60 + '\n')
+ output.write('\n')
+
+
+def remote_initial_comments(file, line):
+ # remote_initial_comments removes any (* *) at the top
+ # of the definition module.
+ while (line.find('*)') == -1):
+ line = file.readline()
+
+
+def removeable_field(line):
+ # removeable_field - 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 (line.find(field) != -1) and (line.find(':') != -1):
+ return True
+ ignore_list = ['System', 'SYSTEM']
+ for ignore_field in ignore_list:
+ if line.find(ignore_field) != -1:
+ if line.find(':') != -1:
+ if line.find('Description:') == -1:
+ return True
+ return False
+
+
+def remove_fields(file, line):
+ # remove_fields removes Author/Date/Last edit/SYSTEM/Revision
+ # fields from a comment within the start of a definition module.
+ while (line.find('*)') == -1):
+ if not removeable_field(line):
+ line = line.rstrip().replace('{', '@{').replace('}', '@}')
+ output.write(line + '\n')
+ line = file.readline()
+ output.write(line.rstrip() + '\n')
+
+
+def emit_index(entry, tag):
+ global state_obj
+ if args.texinfo:
+ if tag == '':
+ output.write('@findex ' + entry.rstrip() + '\n')
+ else:
+ output.write('@findex ' + entry.rstrip() + ' ' + tag + '\n')
+ elif args.sphinx:
+ if tag == '':
+ state_obj.to_index()
+ output.write(' ' * 3 + entry.rstrip() + '\n')
+ else:
+ state_obj.to_index()
+ output.write(' ' * 3 + 'pair: ' + entry.rstrip() + '; ' + tag + '\n')
+
+
+def check_index(line):
+ # check_index - create an index entry for a PROCEDURE, TYPE, CONST or VAR.
+ global state_obj
+
+ words = line.split()
+ procedure = ''
+ if (len(words) > 1) and (words[0] == 'PROCEDURE'):
+ state_obj.set_state(state_none)
+ if (words[1] == '__BUILTIN__') and (len(words) > 2):
+ procedure = words[2]
+ else:
+ procedure = words[1]
+ if (len(line) > 1) and (line[0:2] == '(*'):
+ state_obj.set_state(state_none)
+ elif line == 'VAR':
+ state_obj.set_state(state_var)
+ return
+ elif line == 'TYPE':
+ state_obj.set_state(state_type)
+ return
+ elif line == 'CONST':
+ state_obj.set_state(state_const)
+ if state_obj.is_var():
+ words = line.split(',')
+ for word in words:
+ word = word.lstrip()
+ if word != '':
+ if word.find(':') == -1:
+ emit_index(word, '(var)')
+ elif len(word) > 0:
+ var = word.split(':')
+ if len(var) > 0:
+ emit_index(var[0], '(var)')
+ if state_obj.is_type():
+ words = line.lstrip()
+ if words.find('=') != -1:
+ word = words.split('=')
+ if (len(word[0]) > 0) and (word[0][0] != '_'):
+ emit_index(word[0].rstrip(), '(type)')
+ else:
+ word = words.split()
+ if (len(word) > 1) and (word[1] == ';'):
+ # hidden type
+ if (len(word[0]) > 0) and (word[0][0] != '_'):
+ emit_index(word[0].rstrip(), '(type)')
+ if state_obj.is_const():
+ words = line.split(';')
+ for word in words:
+ word = word.lstrip()
+ if word != '':
+ if word.find('=') != -1:
+ var = word.split('=')
+ if len(var) > 0:
+ emit_index(var[0], '(const)')
+ if procedure != '':
+ name = procedure.split('(')
+ if name[0] != '':
+ proc = name[0]
+ if proc[-1] == ';':
+ proc = proc[:-1]
+ if proc != '':
+ emit_index(proc, '')
+
+def demangle_system_datatype(line, indent):
+ # The spaces in front align in the export qualified list.
+ indent += len ('EXPORT QUALIFIED ')
+ line = line.replace('@SYSTEM_DATATYPES@',
+ '\n' + indent * ' ' + 'Target specific data types.')
+ line = line.replace('@SYSTEM_TYPES@',
+ '(* Target specific data types. *)')
+ return line
+
+
+def emit_texinfo_content(f, line):
+ global state_obj
+ output.write(line.rstrip() + '\n')
+ line = f.readline()
+ if len(line.rstrip()) == 0:
+ output.write('\n')
+ line = f.readline()
+ if (line.find('(*') != -1):
+ remove_fields(f, line)
+ else:
+ output.write(line.rstrip() + '\n')
+ else:
+ output.write(line.rstrip() + '\n')
+ line = f.readline()
+ while line:
+ line = line.rstrip()
+ check_index(line)
+ line = line.replace('{', '@{').replace('}', '@}')
+ line = demangle_system_datatype(line, 0)
+ output.write(line + '\n')
+ line = f.readline()
+ return f
+
+
+def emit_sphinx_content(f, line):
+ global state_obj
+ state_obj.to_code()
+ indentation = 4
+ indent = ' ' * indentation
+ output.write(indent + line.rstrip() + '\n')
+ line = f.readline()
+ if len(line.rstrip()) == 0:
+ output.write('\n')
+ line = f.readline()
+ if (line.find('(*') != -1):
+ remove_fields(f, line)
+ else:
+ output.write(indent + line.rstrip() + '\n')
+ else:
+ output.write(indent + line.rstrip() + '\n')
+ line = f.readline()
+ while line:
+ line = line.rstrip()
+ check_index(line)
+ state_obj.to_code()
+ line = demangle_system_datatype(line, indentation)
+ output.write(indent + line + '\n')
+ line = f.readline()
+ return f
+
+
+def emit_example_content(f, line):
+ if args.texinfo:
+ return emit_texinfo_content(f, line)
+ elif args.sphinx:
+ return emit_sphinx_content(f, line)
+
+
+def emit_example_begin():
+ if args.texinfo:
+ output.write('@example\n')
+
+
+def emit_example_end():
+ if args.texinfo:
+ output.write('@end example\n')
+
+
+def emit_page(need_page):
+ if need_page and args.texinfo:
+ output.write('@page\n')
+
+
+def parse_definition(dir_, source, build, file, need_page):
+ # parse_definition reads a definition module and creates
+ # indices for procedures, constants, variables and types.
+ output.write('\n')
+ with open(find_file(dir_, build, source, file), 'r') as f:
+ init_state()
+ line = f.readline()
+ while (line.find('(*') != -1):
+ remote_initial_comments(f, line)
+ line = f.readline()
+ while (line.find('DEFINITION') == -1):
+ line = f.readline()
+ emit_example_begin()
+ f = emit_example_content(f, line)
+ emit_example_end()
+ emit_page(need_page)
+
+
+def parse_modules(up, dir_, build, source, list_of_modules):
+ previous = ''
+ i = 0
+ if len(list_of_modules) > 1:
+ nxt = dir_ + '/' + list_of_modules[1][:-4]
+ else:
+ nxt = ''
+ while i < len(list_of_modules):
+ emit_node(dir_ + '/' + list_of_modules[i][:-4], nxt, previous, up)
+ emit_sub_section(dir_ + '/' + list_of_modules[i][:-4])
+ parse_definition(dir_, source, build, list_of_modules[i], True)
+ output.write('\n')
+ previous = dir_ + '/' + list_of_modules[i][:-4]
+ i = i + 1
+ if i+1 < len(list_of_modules):
+ nxt = dir_ + '/' + list_of_modules[i+1][:-4]
+ else:
+ nxt = ''
+
+
+def do_cat(name):
+ # do_cat displays the contents of file, name, to stdout
+ with open(name, 'r') as file:
+ line = file.readline()
+ while line:
+ output.write(line.rstrip() + '\n')
+ line = file.readline()
+
+
+def module_menu(dir_, build, source):
+ # module_menu generates a simple menu for all definition modules
+ # in dir
+ output.write('@menu\n')
+ list_of_files = []
+ if os.path.exists(os.path.join(source, dir_)):
+ list_of_files += os.listdir(os.path.join(source, dir_))
+ if os.path.exists(os.path.join(source, dir_)):
+ list_of_files += os.listdir(os.path.join(build, dir_))
+ list_of_files = list(dict.fromkeys(list_of_files).keys())
+ list_of_files.sort()
+ for file in list_of_files:
+ if found_file(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 check_directory(dir_, build, source):
+ # check_directory - 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 found_file(dir_, build, source, file):
+ # found_file 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 find_file(dir_, build, source, file):
+ # find_file 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 display_modules(up, dir_, build, source):
+ # display_modules walks though the files in dir and parses
+ # definition modules and includes README.texi
+ if check_directory(dir_, build, source):
+ if args.texinfo:
+ ext = '.texi'
+ elif args.sphinx:
+ ext = '.rst'
+ else:
+ ext = ''
+ if found_file(dir_, build, source, 'README' + ext):
+ do_cat(find_file(dir_, build, source, 'README' + ext))
+ module_menu(dir_, build, source)
+ list_of_files = []
+ if os.path.exists(os.path.join(source, dir_)):
+ list_of_files += os.listdir(os.path.join(source, dir_))
+ if os.path.exists(os.path.join(source, dir_)):
+ list_of_files += os.listdir(os.path.join(build, dir_))
+ list_of_files = list(dict.fromkeys(list_of_files).keys())
+ list_of_files.sort()
+ list_of_modules = []
+ for file in list_of_files:
+ if found_file(dir_, build, source, file):
+ if (len(file) > 4) and (file[-4:] == '.def'):
+ list_of_modules += [file]
+ list_of_modules.sort()
+ parse_modules(up, dir_, build, source, list_of_modules)
+ else:
+ line = 'directory ' + dir_ + ' not found in either '
+ line += build + ' or ' + source
+ sys.stderr.write(line + '\n')
+
+
+def display_copyright():
+ 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 collect_args():
+ 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 handle_file():
+ if args.inputfile is None:
+ display_copyright()
+ display_menu()
+ display_library_class()
+ else:
+ parse_definition('.', args.sourcedir, args.builddir,
+ args.inputfile, False)
+
+
+def main():
+ global args, output
+ args = collect_args()
+ if args.outputfile is None:
+ output = sys.stdout
+ handle_file()
+ else:
+ with open(args.outputfile, 'w') as output:
+ handle_file()
+
+
+main()
diff --git a/gcc/m2/tools-src/makeSystem b/gcc/m2/tools-src/makeSystem
new file mode 100644
index 0000000..4ff8603
--- /dev/null
+++ b/gcc/m2/tools-src/makeSystem
@@ -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 --git a/gcc/m2/tools-src/mklink.c b/gcc/m2/tools-src/mklink.c
new file mode 100644
index 0000000..fb95fd4
--- /dev/null
+++ b/gcc/m2/tools-src/mklink.c
@@ -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");
+ }
+}
diff --git a/gcc/m2/tools-src/tidydates.py b/gcc/m2/tools-src/tidydates.py
new file mode 100644
index 0000000..c244066
--- /dev/null
+++ b/gcc/m2/tools-src/tidydates.py
@@ -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 pathlib
+import shutil
+import sys
+
+max_line_length = 60
+
+COPYRIGHT = 'Copyright (C)'
+
+
+def visit_dir(directory, ext, func):
+ # visit_dir - call func for each file below, dir, matching extension, ext.
+ list_of_files = os.listdir(directory)
+ list_of_files.sort()
+ for filename in list_of_files:
+ 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):
+ visit_dir(full, ext, func)
+
+
+def is_year(year):
+ # is_year - 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 handle_copyright(outfile, lines, n, leader1, leader2):
+ # handle_copyright look for Copyright in the comment.
+ global max_line_length
+ i = lines[n]
+ c = i.find(COPYRIGHT)+len(COPYRIGHT)
+ outfile.write(i[:c])
+ d = i[c:].split()
+ start = c
+ seen_date = True
+ years = []
+ while seen_date:
+ 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 > max_line_length:
+ outfile.write('\n')
+ outfile.write(leader1)
+ outfile.write(leader2)
+ outfile.write(' '*(start-2))
+ c = start
+ if is_year(e):
+ if (e[-1] == '.') or (e[-1] == ','):
+ punctuation = e[-1]
+ e = e[:-1]
+ else:
+ punctuation = ''
+ else:
+ seen_date = False
+ if seen_date:
+ 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 handle_header(filename, leader1, leader2):
+ # handle_header reads in the header of a file and inserts
+ # a line break around the Copyright dates.
+ print('------------------------------')
+ lines = open(filename).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 = handle_copyright(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 bash_tidy(filename):
+ # bash_tidy - tidy up dates using '#' comment
+ handle_header(filename, '#', ' ')
+
+
+def c_tidy(filename):
+ # c_tidy - tidy up dates using '/* */' comments
+ handle_header(filename, ' ', '*')
+
+
+def m2_tidy(filename):
+ # m2_tidy - tidy up dates using '(* *)' comments
+ handle_header(filename, ' ', ' ')
+
+
+def main():
+ # main - for each file extension call the appropriate tidy routine.
+ visit_dir('.', '.in', bash_tidy)
+ visit_dir('.', '.py', bash_tidy)
+ visit_dir('.', '.c', c_tidy)
+ visit_dir('.', '.h', c_tidy)
+ visit_dir('.', '.def', m2_tidy)
+ visit_dir('.', '.mod', m2_tidy)
+
+
+main()