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.
------8<----------8<----------8<----------8<----------8<----------8<---- diff -ruw /dev/null gcc-git-devel-modula2/mli...@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-12-06 02:56:51.380775219 +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 + +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() 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-12-06 02:56:51.380775219 +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 <ga...@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 -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-12-06 02:56:51.380775219 +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-12-06 02:56:51.380775219 +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.mul...@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-12-06 02:56:51.380775219 +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.mul...@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-12-06 02:56:51.380775219 +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-12-06 02:56:51.380775219 +0000 @@ -0,0 +1,519 @@ +#!/usr/bin/env python3 + +# def2doc.py creates texi library documentation for all exported procedures. +# Contributed by Gaius Mulley <gaius.mul...@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): + output.write(str.replace(str.replace(str.rstrip(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 emit_texinfo_content(f, line): + global state_obj + state_obj.to_code() + 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) + state_obj.to_code() + output.write(str.replace(str.replace(line, '{', '@{'), '}', '@}')) + output.write('\n') + line = f.readline() + return f + + +def emit_sphinx_content(f, line): + global state_obj + state_obj.to_code() + indent = ' ' * 4 + 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() + 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 -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-12-06 02:56:51.380775219 +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 <ga...@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"); + } +}