This pass makes sure all brackets (parenthesis) are matched in the
source program.

Signed-off-by: Jose E. Marchesi <[email protected]>
Co-authored-by: Marcel van der Veer <[email protected]>
---
 gcc/algol68/a68-parser-brackets.cc | 226 +++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)
 create mode 100644 gcc/algol68/a68-parser-brackets.cc

diff --git a/gcc/algol68/a68-parser-brackets.cc 
b/gcc/algol68/a68-parser-brackets.cc
new file mode 100644
index 00000000000..2aaa77024ec
--- /dev/null
+++ b/gcc/algol68/a68-parser-brackets.cc
@@ -0,0 +1,226 @@
+/* Recursive-descent parenthesis checker.
+   Copyright (C) 2001-2023 J. Marcel van der Veer.
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   Original implementation by J. Marcel van der Veer.
+   Adapted for GCC by Jose E. Marchesi.
+
+   GCC 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.
+
+   GCC 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 GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "a68.h"
+
+/* After this checker, we know that at least brackets are matched.  This
+   stabilises later parser phases.
+
+   Note that this checker operates on a linear list of nodes.
+
+   Error diagnostics are placed near offending lines.  */
+
+/* Intelligible diagnostics for the bracket checker.  */
+
+static void
+bracket_check_error (char *txt, int n, const char *bra, const char *ket)
+{
+  BUFFER buf;
+
+  if (n == 0)
+    return;
+
+  char *strop_ket = a68_strop_keyword (ket);
+  char *strop_bra = a68_strop_keyword (bra);
+
+  BUFCLR (buf);
+  if (snprintf (buf, SNPRINTF_SIZE, "missing matching %%<%s%%>",
+               (n > 0 ? strop_ket : strop_bra)) < 0)
+    gcc_unreachable ();
+
+  free (strop_ket);
+  free (strop_bra);
+
+  if (strlen (txt) > 0)
+    a68_bufcat (txt, " or ", BUFFER_SIZE);
+  a68_bufcat (txt, buf, BUFFER_SIZE);
+}
+
+/* Diagnose brackets in local branch of the tree.  */
+
+static char *
+bracket_check_diagnose (NODE_T *p)
+{
+  int begins = 0, opens = 0, format_delims = 0, format_opens = 0;
+  int subs = 0, ifs = 0, cases = 0, dos = 0;
+
+  for (; p != NO_NODE; FORWARD (p))
+    {
+      switch (ATTRIBUTE (p))
+       {
+       case BEGIN_SYMBOL:
+         begins++;
+         break;
+       case END_SYMBOL:
+         begins--;
+         break;
+       case OPEN_SYMBOL:
+         opens++;
+         break;
+       case CLOSE_SYMBOL:
+         opens--;
+         break;
+       case FORMAT_DELIMITER_SYMBOL:
+         if (format_delims == 0)
+           format_delims = 1;
+         else
+           format_delims = 0;
+         break;
+       case FORMAT_OPEN_SYMBOL:
+         format_opens++;
+         break;
+       case FORMAT_CLOSE_SYMBOL:
+         format_opens--;
+         break;
+       case SUB_SYMBOL:
+         subs++;
+         break;
+       case BUS_SYMBOL:
+         subs--;
+         break;
+       case IF_SYMBOL:
+         ifs++;
+         break;
+       case FI_SYMBOL:
+         ifs--;
+         break;
+       case CASE_SYMBOL:
+         cases++;
+         break;
+       case ESAC_SYMBOL:
+         cases--;
+         break;
+       case DO_SYMBOL:
+         dos++;
+         break;
+       case OD_SYMBOL:
+         dos--;
+         break;
+       default:
+         break;
+       }
+    }
+
+  A68 (edit_line)[0] = '\0';
+  bracket_check_error (A68 (edit_line), begins, "BEGIN", "END");
+  bracket_check_error (A68 (edit_line), opens, "(", ")");
+  bracket_check_error (A68 (edit_line), format_opens, "(", ")");
+  bracket_check_error (A68 (edit_line), format_delims, "$", "$");
+  bracket_check_error (A68 (edit_line), subs, "[", "]");
+  bracket_check_error (A68 (edit_line), ifs, "IF", "FI");
+  bracket_check_error (A68 (edit_line), cases, "CASE", "ESAC");
+  bracket_check_error (A68 (edit_line), dos, "DO", "OD");
+  return A68 (edit_line);
+}
+
+/* Driver for locally diagnosing non-matching tokens.  */
+
+static NODE_T *
+bracket_check_parse (NODE_T *top, NODE_T *p)
+{
+  for (; p != NO_NODE; FORWARD (p))
+    {
+      int ket = STOP;
+      NODE_T *q = NO_NODE;
+      bool ignore_token = false;
+
+      switch (ATTRIBUTE (p))
+       {
+       case BEGIN_SYMBOL:
+         ket = END_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case OPEN_SYMBOL:
+         ket = CLOSE_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case FORMAT_OPEN_SYMBOL:
+         ket = FORMAT_CLOSE_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case SUB_SYMBOL:
+         ket = BUS_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case IF_SYMBOL:
+         ket = FI_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case CASE_SYMBOL:
+         ket = ESAC_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case DO_SYMBOL:
+         ket = OD_SYMBOL;
+         q = bracket_check_parse (top, NEXT (p));
+         break;
+       case END_SYMBOL:
+       case CLOSE_SYMBOL:
+       case FORMAT_CLOSE_SYMBOL:
+       case BUS_SYMBOL:
+       case FI_SYMBOL:
+       case ESAC_SYMBOL:
+       case OD_SYMBOL:
+         return p;
+       default:
+         ignore_token = true;
+       }
+
+      if (ignore_token)
+       ;
+      else if (q != NO_NODE && IS (q, ket))
+       p = q;
+      else if (q == NO_NODE)
+       {
+         char *diag = bracket_check_diagnose (top);
+         a68_error (p, "incorrect nesting, check for Y",
+                    (strlen (diag) > 0 ? diag : "missing or unmatched 
keyword"));
+         longjmp (A68_PARSER (top_down_crash_exit), 1);
+       }
+      else
+       {
+         char *diag = bracket_check_diagnose (top);
+         a68_error (q, "unexpected X, check for Y",
+                    ATTRIBUTE (q),
+                    (strlen (diag) > 0 ? diag : "missing or unmatched 
keyword"));
+         longjmp (A68_PARSER (top_down_crash_exit), 1);
+       }
+    }
+  return NO_NODE;
+}
+
+/* Driver for globally diagnosing non-matching tokens.  */
+
+void
+a68_check_parenthesis (NODE_T *top)
+{
+  if (!setjmp (A68_PARSER (top_down_crash_exit)))
+    {
+      if (bracket_check_parse (top, top) != NO_NODE)
+       a68_error (top, "incorrect nesting, check for Y",
+                  "missing or unmatched keyword");
+    }
+}
-- 
2.30.2

Reply via email to