Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: simon.marchi@polymtl.ca
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@polymtl.ca>
Subject: [PATCH 16/17] gdb: move m2-exp-parser.y's support code to m2-exp-parser.c
Date: Fri,  4 Sep 2026 12:56:48 -0400	[thread overview]
Message-ID: <20260904170338.1643894-17-simon.marchi@polymtl.ca> (raw)
In-Reply-To: <20260904170338.1643894-1-simon.marchi@polymtl.ca>

From: Simon Marchi <simon.marchi@polymtl.ca>

Similar to the previous commits, but for the Modula-2 expression parser.

Like the Fortran parser, the Modula-2 parser is entered through the
m2_language::parser method rather than a free function, so add a free
function m2_parse as the entry point (like the other parsers) and turn
m2_language::parser into a thin wrapper around it, defined in m2-lang.c.

Put the parser support code inside the m2_exp_parser namespace.

Change-Id: I92669a1af7fb81cf59bfb41e2b8c63ce323652d2
---
 gdb/Makefile.in     |   2 +
 gdb/m2-exp-parser.c | 488 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/m2-exp-parser.h |  67 ++++++
 gdb/m2-exp-parser.y | 465 +----------------------------------------
 gdb/m2-lang.c       |   9 +
 5 files changed, 568 insertions(+), 463 deletions(-)
 create mode 100644 gdb/m2-exp-parser.c
 create mode 100644 gdb/m2-exp-parser.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4289c5151fd0..1c4ba5a12d57 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1137,6 +1137,7 @@ COMMON_SFILES = \
 	language.c \
 	linespec.c \
 	location.c \
+	m2-exp-parser.c \
 	m2-lang.c \
 	m2-typeprint.c \
 	m2-valprint.c \
@@ -1518,6 +1519,7 @@ HFILES_NO_SRCDIR = \
 	linux-tdep.h \
 	location.h \
 	loongarch-tdep.h \
+	m2-exp-parser.h \
 	m2-exp.h \
 	m2-lang.h \
 	m32r-tdep.h \
diff --git a/gdb/m2-exp-parser.c b/gdb/m2-exp-parser.c
new file mode 100644
index 000000000000..821f1507aef3
--- /dev/null
+++ b/gdb/m2-exp-parser.c
@@ -0,0 +1,488 @@
+/* YACC parser support code for Modula-2 expressions, for GDB.
+
+   Copyright (C) 1986-2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "m2-exp-parser.h"
+#include "m2-exp-parser-gen.h"
+#include "block.h"
+#include "expression.h"
+#include "language.h"
+#include "m2-exp.h"
+#include "parser-defs.h"
+#include "value.h"
+
+/* The entry point of the bison/yacc-generated parser, defined in
+   m2-exp-parser-gen.c.  Bison produces a declaration for m2_yyparse in
+   m2-exp-parser-gen.h, but byacc does not, hence this declaration.  */
+
+int m2_yyparse ();
+
+/* Likewise, byacc does not produce a declaration for m2_yydebug.  */
+
+extern int m2_yydebug;
+
+namespace m2_exp_parser
+{
+
+/* See m2-exp-parser.h.  */
+
+parser_state *pstate;
+
+/* See m2-exp-parser.h.  */
+
+int number_sign = 1;
+
+/* Take care of parsing a number (anything that starts with a digit).
+   Set yylval and return the token type; update lexptr.
+   LEN is the number of characters in it.  */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (int olen)
+{
+  const char *p = pstate->lexptr;
+  ULONGEST n = 0;
+  ULONGEST prevn = 0;
+  int c,i,ischar=0;
+  int base = input_radix;
+  int len = olen;
+
+  if(p[len-1] == 'H')
+  {
+     base = 16;
+     len--;
+  }
+  else if(p[len-1] == 'C' || p[len-1] == 'B')
+  {
+     base = 8;
+     ischar = p[len-1] == 'C';
+     len--;
+  }
+
+  /* Scan the number */
+  for (c = 0; c < len; c++)
+  {
+    if (p[c] == '.' && base == 10)
+      {
+	/* It's a float since it contains a point.  */
+	if (!parse_float (p, len,
+			  parse_m2_type (pstate)->builtin_real,
+			  m2_yylval.val))
+	  return ERROR;
+
+	pstate->lexptr += len;
+	return FLOAT;
+      }
+    if (p[c] == '.' && base != 10)
+       error (_("Floating point numbers must be base 10."));
+    if (base == 10 && (p[c] < '0' || p[c] > '9'))
+       error (_("Invalid digit \'%c\' in number."),p[c]);
+ }
+
+  while (len-- > 0)
+    {
+      c = *p++;
+      n *= base;
+      if( base == 8 && (c == '8' || c == '9'))
+	 error (_("Invalid digit \'%c\' in octal number."),c);
+      if (c >= '0' && c <= '9')
+	i = c - '0';
+      else
+	{
+	  if (base == 16 && c >= 'A' && c <= 'F')
+	    i = c - 'A' + 10;
+	  else
+	     return ERROR;
+	}
+      n+=i;
+      if(i >= base)
+	 return ERROR;
+      if (n == 0 && prevn == 0)
+	;
+      else if (RANGE_CHECK && prevn >= n)
+	range_error (_("Overflow on numeric constant."));
+
+	 prevn=n;
+    }
+
+  pstate->lexptr = p;
+  if(*p == 'B' || *p == 'C' || *p == 'H')
+     pstate->lexptr++;			/* Advance past B,C or H */
+
+  if (ischar)
+  {
+     m2_yylval.ulval = n;
+     return CHAR;
+  }
+
+  int int_bits = gdbarch_int_bit (pstate->gdbarch ());
+  bool have_signed = number_sign == -1;
+  bool have_unsigned = number_sign == 1;
+  if (have_signed && fits_in_type (number_sign, n, int_bits, true))
+    {
+      m2_yylval.lval = n;
+      return INT;
+    }
+  else if (have_unsigned && fits_in_type (number_sign, n, int_bits, false))
+    {
+      m2_yylval.ulval = n;
+      return UINT;
+    }
+  else
+    error (_("Overflow on numeric constant."));
+}
+
+/* Some tokens */
+
+static struct
+{
+   char name[2];
+   int token;
+} tokentab2[] =
+{
+    { {'<', '>'},    NOTEQUAL 	},
+    { {':', '='},    ASSIGN	},
+    { {'<', '='},    LEQ	},
+    { {'>', '='},    GEQ	},
+    { {':', ':'},    COLONCOLON },
+
+};
+
+/* Some specific keywords */
+
+struct keyword {
+   char keyw[10];
+   int token;
+};
+
+static struct keyword keytab[] =
+{
+    {"OR" ,   OROR	 },
+    {"IN",    IN         },/* Note space after IN */
+    {"AND",   LOGICAL_AND},
+    {"ABS",   ABS	 },
+    {"ADR",   ADR	 },
+    {"CHR",   CHR	 },
+    {"DEC",   DEC	 },
+    {"NOT",   NOT	 },
+    {"DIV",   DIV    	 },
+    {"INC",   INC	 },
+    {"MAX",   MAX_FUNC	 },
+    {"MIN",   MIN_FUNC	 },
+    {"MOD",   MOD	 },
+    {"ODD",   ODD	 },
+    {"CAP",   CAP	 },
+    {"ORD",   ORD	 },
+    {"VAL",   VAL	 },
+    {"EXCL",  EXCL	 },
+    {"HIGH",  HIGH       },
+    {"INCL",  INCL	 },
+    {"SIZE",  SIZE       },
+    {"FLOAT", FLOAT_FUNC },
+    {"TRUNC", TRUNC	 },
+    {"TSIZE", SIZE       },
+};
+
+/* Depth of parentheses.  */
+static int paren_depth;
+
+/* See m2-exp-parser.h.  */
+
+int
+m2_yylex (void)
+{
+  int c;
+  int namelen;
+  int i;
+  const char *tokstart;
+  char quote;
+
+ retry:
+
+  pstate->prev_lexptr = pstate->lexptr;
+
+  tokstart = pstate->lexptr;
+
+
+  /* See if it is a special token of length 2 */
+  for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++)
+     if (strncmp (tokentab2[i].name, tokstart, 2) == 0)
+     {
+	pstate->lexptr += 2;
+	return tokentab2[i].token;
+     }
+
+  switch (c = *tokstart)
+    {
+    case 0:
+      return 0;
+
+    case ' ':
+    case '\t':
+    case '\n':
+      pstate->lexptr++;
+      goto retry;
+
+    case '(':
+      paren_depth++;
+      pstate->lexptr++;
+      return c;
+
+    case ')':
+      if (paren_depth == 0)
+	return 0;
+      paren_depth--;
+      pstate->lexptr++;
+      return c;
+
+    case ',':
+      if (pstate->comma_terminates && paren_depth == 0)
+	return 0;
+      pstate->lexptr++;
+      return c;
+
+    case '.':
+      /* Might be a floating point number.  */
+      if (pstate->lexptr[1] >= '0' && pstate->lexptr[1] <= '9')
+	break;			/* Falls into number code.  */
+      else
+      {
+	 pstate->lexptr++;
+	 return DOT;
+      }
+
+/* These are character tokens that appear as-is in the YACC grammar */
+    case '+':
+    case '-':
+    case '*':
+    case '/':
+    case '^':
+    case '<':
+    case '>':
+    case '[':
+    case ']':
+    case '=':
+    case '{':
+    case '}':
+    case '#':
+    case '@':
+    case '~':
+    case '&':
+      pstate->lexptr++;
+      return c;
+
+    case '\'' :
+    case '"':
+      quote = c;
+      for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++)
+	if (c == '\\')
+	  {
+	    c = tokstart[++namelen];
+	    if (c >= '0' && c <= '9')
+	      {
+		c = tokstart[++namelen];
+		if (c >= '0' && c <= '9')
+		  c = tokstart[++namelen];
+	      }
+	  }
+      if(c != quote)
+	 error (_("Unterminated string or character constant."));
+      m2_yylval.sval.ptr = tokstart + 1;
+      m2_yylval.sval.length = namelen - 1;
+      pstate->lexptr += namelen + 1;
+
+      if(namelen == 2)  	/* Single character */
+      {
+	   m2_yylval.ulval = tokstart[1];
+	   return CHAR;
+      }
+      else
+	 return STRING;
+    }
+
+  /* Is it a number?  */
+  /* Note:  We have already dealt with the case of the token '.'.
+     See case '.' above.  */
+  if ((c >= '0' && c <= '9'))
+    {
+      /* It's a number.  */
+      int got_dot = 0, got_e = 0;
+      const char *p = tokstart;
+      int toktype;
+
+      for (++p ;; ++p)
+	{
+	  if (!got_e && (*p == 'e' || *p == 'E'))
+	    got_dot = got_e = 1;
+	  else if (!got_dot && *p == '.')
+	    got_dot = 1;
+	  else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+		   && (*p == '-' || *p == '+'))
+	    /* This is the sign of the exponent, not the end of the
+	       number.  */
+	    continue;
+	  else if ((*p < '0' || *p > '9') &&
+		   (*p < 'A' || *p > 'F') &&
+		   (*p != 'H'))  /* Modula-2 hexadecimal number */
+	    break;
+	}
+	toktype = parse_number (p - tokstart);
+	if (toktype == ERROR)
+	  error (_("Invalid number \"%.*s\"."), (int) (p - tokstart),
+		 tokstart);
+	pstate->lexptr = p;
+	return toktype;
+    }
+
+  if (!(c == '_' || c == '$'
+	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+    /* We must have come across a bad character (e.g. ';').  */
+    error (_("Invalid character '%c' in expression."), c);
+
+  /* It's a name.  See how long it is.  */
+  namelen = 0;
+  for (c = tokstart[namelen];
+       (c == '_' || c == '$' || (c >= '0' && c <= '9')
+	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+       c = tokstart[++namelen])
+    ;
+
+  /* The token "if" terminates the expression and is NOT
+     removed from the input stream.  */
+  if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+    {
+      return 0;
+    }
+
+  pstate->lexptr += namelen;
+
+  /*  Lookup special keywords */
+  for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++)
+     if (namelen == strlen (keytab[i].keyw)
+	 && strncmp (tokstart, keytab[i].keyw, namelen) == 0)
+	   return keytab[i].token;
+
+  m2_yylval.sval.ptr = tokstart;
+  m2_yylval.sval.length = namelen;
+
+  if (*tokstart == '$')
+    return DOLLAR_VARIABLE;
+
+  /* Use token-type BLOCKNAME for symbols that happen to be defined as
+     functions.  If this is not so, then ...
+     Use token-type TYPENAME for symbols that happen to be defined
+     currently as names of types; NAME for other symbols.
+     The caller is not constrained to care about the distinction.  */
+ {
+    std::string tmp = copy_name (m2_yylval.sval);
+    struct symbol *sym;
+
+    if (lookup_symtab (current_program_space, tmp.c_str ()) != nullptr)
+      return BLOCKNAME;
+
+    sym = lookup_symbol (tmp.c_str (), pstate->expression_context_block,
+			 SEARCH_VFT, 0).symbol;
+    if (sym && sym->loc_class () == LOC_BLOCK)
+      return BLOCKNAME;
+    if (lookup_typename (pstate->language (),
+			 tmp.c_str (), pstate->expression_context_block, 1))
+      return TYPENAME;
+
+    if(sym)
+    {
+      switch(sym->loc_class ())
+       {
+       case LOC_STATIC:
+       case LOC_REGISTER:
+       case LOC_ARG:
+       case LOC_REF_ARG:
+       case LOC_REGPARM_ADDR:
+       case LOC_LOCAL:
+       case LOC_CONST:
+       case LOC_CONST_BYTES:
+       case LOC_OPTIMIZED_OUT:
+       case LOC_COMPUTED:
+	  return NAME;
+
+       case LOC_TYPEDEF:
+	  return TYPENAME;
+
+       case LOC_BLOCK:
+	  return BLOCKNAME;
+
+       case LOC_UNDEF:
+	  error (_("internal:  Undefined class in m2lex()"));
+
+       case LOC_LABEL:
+       case LOC_UNRESOLVED:
+	  error (_("internal:  Unforeseen case in m2lex()"));
+
+       default:
+	  error (_("unhandled token in m2lex()"));
+	  break;
+       }
+    }
+    else
+    {
+       /* Built-in BOOLEAN type.  This is sort of a hack.  */
+       if (startswith (tokstart, "TRUE"))
+       {
+	  m2_yylval.ulval = 1;
+	  return M2_TRUE;
+       }
+       else if (startswith (tokstart, "FALSE"))
+       {
+	  m2_yylval.ulval = 0;
+	  return M2_FALSE;
+       }
+    }
+
+    /* Must be another type of name...  */
+    return NAME;
+ }
+}
+
+/* See m2-exp-parser.h.  */
+
+void
+m2_yyerror (const char *msg)
+{
+  pstate->parse_error (msg);
+}
+
+} /* namespace m2_exp_parser */
+
+/* See m2-exp-parser.h.  */
+
+int
+m2_parse (struct parser_state *par_state)
+{
+  using namespace m2_exp_parser;
+
+  /* Setting up the parser state.  */
+  scoped_restore pstate_restore = make_scoped_restore (&pstate);
+  gdb_assert (par_state != NULL);
+  pstate = par_state;
+  paren_depth = 0;
+
+  int result = m2_yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
+}
diff --git a/gdb/m2-exp-parser.h b/gdb/m2-exp-parser.h
new file mode 100644
index 000000000000..bea7155188fb
--- /dev/null
+++ b/gdb/m2-exp-parser.h
@@ -0,0 +1,67 @@
+/* YACC parser support code for Modula-2 expressions, for GDB.
+
+   Copyright (C) 1986-2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_M2_EXP_PARSER_H
+#define GDB_M2_EXP_PARSER_H
+
+#include "parser-defs.h"
+#include "m2-lang.h"
+
+union m2_exp_parser_YYSTYPE;
+
+namespace m2_exp_parser {
+
+/* The state of the parser, used internally when we are parsing the
+   expression.  */
+
+extern parser_state *pstate;
+
+/* The sign of the number being parsed.  */
+
+extern int number_sign;
+
+/* Return the Modula-2 type table for the architecture associated to PS.  */
+
+static inline const struct builtin_m2_type *
+parse_m2_type (parser_state *ps)
+{
+  return builtin_m2_type (ps->gdbarch ());
+}
+
+/* Read one token, getting characters through lexptr.  */
+
+/* This is where we will check to make sure that the language and the
+   operators used are compatible  */
+
+int m2_yylex ();
+
+/* The error handler invoked by the generated parser.  Report MSG as a
+   parse error on the current parser state.  */
+
+void m2_yyerror (const char *msg);
+
+} /* namespace m2_exp_parser */
+
+/* Parse a Modula-2 expression using the lexer input and context held in
+   PAR_STATE.  On success, return 0 and leave the resulting operation set
+   on PAR_STATE.  On failure, return non-zero.  */
+
+int m2_parse (struct parser_state *par_state);
+
+#endif /* GDB_M2_EXP_PARSER_H */
diff --git a/gdb/m2-exp-parser.y b/gdb/m2-exp-parser.y
index 0f1c62c7ae52..a10087fa03ab 100644
--- a/gdb/m2-exp-parser.y
+++ b/gdb/m2-exp-parser.y
@@ -42,33 +42,11 @@
 #include "value.h"
 #include "parser-defs.h"
 #include "m2-lang.h"
+#include "m2-exp-parser.h"
 #include "block.h"
 #include "m2-exp.h"
 
-/* The state of the parser, used internally when we are parsing the
-   expression.  */
-
-static struct parser_state *pstate = NULL;
-
-int yyparse (void);
-
-static int yylex (void);
-
-static void yyerror (const char *);
-
-static int parse_number (int);
-
-/* The sign of the number being parsed.  */
-static int number_sign = 1;
-
-/* Return the Modula-2 type table for the architecture associated to PS.  */
-
-static inline const struct builtin_m2_type *
-parse_m2_type (parser_state *ps)
-{
-  return builtin_m2_type (ps->gdbarch ());
-}
-
+using namespace m2_exp_parser;
 using namespace expr;
 %}
 
@@ -569,442 +547,3 @@ type
 			}
 
 	;
-
-%%
-
-/* Take care of parsing a number (anything that starts with a digit).
-   Set yylval and return the token type; update lexptr.
-   LEN is the number of characters in it.  */
-
-/*** Needs some error checking for the float case ***/
-
-static int
-parse_number (int olen)
-{
-  const char *p = pstate->lexptr;
-  ULONGEST n = 0;
-  ULONGEST prevn = 0;
-  int c,i,ischar=0;
-  int base = input_radix;
-  int len = olen;
-
-  if(p[len-1] == 'H')
-  {
-     base = 16;
-     len--;
-  }
-  else if(p[len-1] == 'C' || p[len-1] == 'B')
-  {
-     base = 8;
-     ischar = p[len-1] == 'C';
-     len--;
-  }
-
-  /* Scan the number */
-  for (c = 0; c < len; c++)
-  {
-    if (p[c] == '.' && base == 10)
-      {
-	/* It's a float since it contains a point.  */
-	if (!parse_float (p, len,
-			  parse_m2_type (pstate)->builtin_real,
-			  yylval.val))
-	  return ERROR;
-
-	pstate->lexptr += len;
-	return FLOAT;
-      }
-    if (p[c] == '.' && base != 10)
-       error (_("Floating point numbers must be base 10."));
-    if (base == 10 && (p[c] < '0' || p[c] > '9'))
-       error (_("Invalid digit \'%c\' in number."),p[c]);
- }
-
-  while (len-- > 0)
-    {
-      c = *p++;
-      n *= base;
-      if( base == 8 && (c == '8' || c == '9'))
-	 error (_("Invalid digit \'%c\' in octal number."),c);
-      if (c >= '0' && c <= '9')
-	i = c - '0';
-      else
-	{
-	  if (base == 16 && c >= 'A' && c <= 'F')
-	    i = c - 'A' + 10;
-	  else
-	     return ERROR;
-	}
-      n+=i;
-      if(i >= base)
-	 return ERROR;
-      if (n == 0 && prevn == 0)
-	;
-      else if (RANGE_CHECK && prevn >= n)
-	range_error (_("Overflow on numeric constant."));
-
-	 prevn=n;
-    }
-
-  pstate->lexptr = p;
-  if(*p == 'B' || *p == 'C' || *p == 'H')
-     pstate->lexptr++;			/* Advance past B,C or H */
-
-  if (ischar)
-  {
-     yylval.ulval = n;
-     return CHAR;
-  }
-
-  int int_bits = gdbarch_int_bit (pstate->gdbarch ());
-  bool have_signed = number_sign == -1;
-  bool have_unsigned = number_sign == 1;
-  if (have_signed && fits_in_type (number_sign, n, int_bits, true))
-    {
-      yylval.lval = n;
-      return INT;
-    }
-  else if (have_unsigned && fits_in_type (number_sign, n, int_bits, false))
-    {
-      yylval.ulval = n;
-      return UINT;
-    }
-  else
-    error (_("Overflow on numeric constant."));
-}
-
-
-/* Some tokens */
-
-static struct
-{
-   char name[2];
-   int token;
-} tokentab2[] =
-{
-    { {'<', '>'},    NOTEQUAL 	},
-    { {':', '='},    ASSIGN	},
-    { {'<', '='},    LEQ	},
-    { {'>', '='},    GEQ	},
-    { {':', ':'},    COLONCOLON },
-
-};
-
-/* Some specific keywords */
-
-struct keyword {
-   char keyw[10];
-   int token;
-};
-
-static struct keyword keytab[] =
-{
-    {"OR" ,   OROR	 },
-    {"IN",    IN         },/* Note space after IN */
-    {"AND",   LOGICAL_AND},
-    {"ABS",   ABS	 },
-    {"ADR",   ADR	 },
-    {"CHR",   CHR	 },
-    {"DEC",   DEC	 },
-    {"NOT",   NOT	 },
-    {"DIV",   DIV    	 },
-    {"INC",   INC	 },
-    {"MAX",   MAX_FUNC	 },
-    {"MIN",   MIN_FUNC	 },
-    {"MOD",   MOD	 },
-    {"ODD",   ODD	 },
-    {"CAP",   CAP	 },
-    {"ORD",   ORD	 },
-    {"VAL",   VAL	 },
-    {"EXCL",  EXCL	 },
-    {"HIGH",  HIGH       },
-    {"INCL",  INCL	 },
-    {"SIZE",  SIZE       },
-    {"FLOAT", FLOAT_FUNC },
-    {"TRUNC", TRUNC	 },
-    {"TSIZE", SIZE       },
-};
-
-
-/* Depth of parentheses.  */
-static int paren_depth;
-
-/* Read one token, getting characters through lexptr.  */
-
-/* This is where we will check to make sure that the language and the
-   operators used are compatible  */
-
-static int
-yylex (void)
-{
-  int c;
-  int namelen;
-  int i;
-  const char *tokstart;
-  char quote;
-
- retry:
-
-  pstate->prev_lexptr = pstate->lexptr;
-
-  tokstart = pstate->lexptr;
-
-
-  /* See if it is a special token of length 2 */
-  for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++)
-     if (strncmp (tokentab2[i].name, tokstart, 2) == 0)
-     {
-	pstate->lexptr += 2;
-	return tokentab2[i].token;
-     }
-
-  switch (c = *tokstart)
-    {
-    case 0:
-      return 0;
-
-    case ' ':
-    case '\t':
-    case '\n':
-      pstate->lexptr++;
-      goto retry;
-
-    case '(':
-      paren_depth++;
-      pstate->lexptr++;
-      return c;
-
-    case ')':
-      if (paren_depth == 0)
-	return 0;
-      paren_depth--;
-      pstate->lexptr++;
-      return c;
-
-    case ',':
-      if (pstate->comma_terminates && paren_depth == 0)
-	return 0;
-      pstate->lexptr++;
-      return c;
-
-    case '.':
-      /* Might be a floating point number.  */
-      if (pstate->lexptr[1] >= '0' && pstate->lexptr[1] <= '9')
-	break;			/* Falls into number code.  */
-      else
-      {
-	 pstate->lexptr++;
-	 return DOT;
-      }
-
-/* These are character tokens that appear as-is in the YACC grammar */
-    case '+':
-    case '-':
-    case '*':
-    case '/':
-    case '^':
-    case '<':
-    case '>':
-    case '[':
-    case ']':
-    case '=':
-    case '{':
-    case '}':
-    case '#':
-    case '@':
-    case '~':
-    case '&':
-      pstate->lexptr++;
-      return c;
-
-    case '\'' :
-    case '"':
-      quote = c;
-      for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++)
-	if (c == '\\')
-	  {
-	    c = tokstart[++namelen];
-	    if (c >= '0' && c <= '9')
-	      {
-		c = tokstart[++namelen];
-		if (c >= '0' && c <= '9')
-		  c = tokstart[++namelen];
-	      }
-	  }
-      if(c != quote)
-	 error (_("Unterminated string or character constant."));
-      yylval.sval.ptr = tokstart + 1;
-      yylval.sval.length = namelen - 1;
-      pstate->lexptr += namelen + 1;
-
-      if(namelen == 2)  	/* Single character */
-      {
-	   yylval.ulval = tokstart[1];
-	   return CHAR;
-      }
-      else
-	 return STRING;
-    }
-
-  /* Is it a number?  */
-  /* Note:  We have already dealt with the case of the token '.'.
-     See case '.' above.  */
-  if ((c >= '0' && c <= '9'))
-    {
-      /* It's a number.  */
-      int got_dot = 0, got_e = 0;
-      const char *p = tokstart;
-      int toktype;
-
-      for (++p ;; ++p)
-	{
-	  if (!got_e && (*p == 'e' || *p == 'E'))
-	    got_dot = got_e = 1;
-	  else if (!got_dot && *p == '.')
-	    got_dot = 1;
-	  else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
-		   && (*p == '-' || *p == '+'))
-	    /* This is the sign of the exponent, not the end of the
-	       number.  */
-	    continue;
-	  else if ((*p < '0' || *p > '9') &&
-		   (*p < 'A' || *p > 'F') &&
-		   (*p != 'H'))  /* Modula-2 hexadecimal number */
-	    break;
-	}
-	toktype = parse_number (p - tokstart);
-	if (toktype == ERROR)
-	  error (_("Invalid number \"%.*s\"."), (int) (p - tokstart),
-		 tokstart);
-	pstate->lexptr = p;
-	return toktype;
-    }
-
-  if (!(c == '_' || c == '$'
-	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
-    /* We must have come across a bad character (e.g. ';').  */
-    error (_("Invalid character '%c' in expression."), c);
-
-  /* It's a name.  See how long it is.  */
-  namelen = 0;
-  for (c = tokstart[namelen];
-       (c == '_' || c == '$' || (c >= '0' && c <= '9')
-	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
-       c = tokstart[++namelen])
-    ;
-
-  /* The token "if" terminates the expression and is NOT
-     removed from the input stream.  */
-  if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
-    {
-      return 0;
-    }
-
-  pstate->lexptr += namelen;
-
-  /*  Lookup special keywords */
-  for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++)
-     if (namelen == strlen (keytab[i].keyw)
-	 && strncmp (tokstart, keytab[i].keyw, namelen) == 0)
-	   return keytab[i].token;
-
-  yylval.sval.ptr = tokstart;
-  yylval.sval.length = namelen;
-
-  if (*tokstart == '$')
-    return DOLLAR_VARIABLE;
-
-  /* Use token-type BLOCKNAME for symbols that happen to be defined as
-     functions.  If this is not so, then ...
-     Use token-type TYPENAME for symbols that happen to be defined
-     currently as names of types; NAME for other symbols.
-     The caller is not constrained to care about the distinction.  */
- {
-    std::string tmp = copy_name (yylval.sval);
-    struct symbol *sym;
-
-    if (lookup_symtab (current_program_space, tmp.c_str ()) != nullptr)
-      return BLOCKNAME;
-
-    sym = lookup_symbol (tmp.c_str (), pstate->expression_context_block,
-			 SEARCH_VFT, 0).symbol;
-    if (sym && sym->loc_class () == LOC_BLOCK)
-      return BLOCKNAME;
-    if (lookup_typename (pstate->language (),
-			 tmp.c_str (), pstate->expression_context_block, 1))
-      return TYPENAME;
-
-    if(sym)
-    {
-      switch(sym->loc_class ())
-       {
-       case LOC_STATIC:
-       case LOC_REGISTER:
-       case LOC_ARG:
-       case LOC_REF_ARG:
-       case LOC_REGPARM_ADDR:
-       case LOC_LOCAL:
-       case LOC_CONST:
-       case LOC_CONST_BYTES:
-       case LOC_OPTIMIZED_OUT:
-       case LOC_COMPUTED:
-	  return NAME;
-
-       case LOC_TYPEDEF:
-	  return TYPENAME;
-
-       case LOC_BLOCK:
-	  return BLOCKNAME;
-
-       case LOC_UNDEF:
-	  error (_("internal:  Undefined class in m2lex()"));
-
-       case LOC_LABEL:
-       case LOC_UNRESOLVED:
-	  error (_("internal:  Unforeseen case in m2lex()"));
-
-       default:
-	  error (_("unhandled token in m2lex()"));
-	  break;
-       }
-    }
-    else
-    {
-       /* Built-in BOOLEAN type.  This is sort of a hack.  */
-       if (startswith (tokstart, "TRUE"))
-       {
-	  yylval.ulval = 1;
-	  return M2_TRUE;
-       }
-       else if (startswith (tokstart, "FALSE"))
-       {
-	  yylval.ulval = 0;
-	  return M2_FALSE;
-       }
-    }
-
-    /* Must be another type of name...  */
-    return NAME;
- }
-}
-
-int
-m2_language::parser (struct parser_state *par_state) const
-{
-  /* Setting up the parser state.  */
-  scoped_restore pstate_restore = make_scoped_restore (&pstate);
-  gdb_assert (par_state != NULL);
-  pstate = par_state;
-  paren_depth = 0;
-
-  int result = yyparse ();
-  if (!result)
-    pstate->set_operation (pstate->pop ());
-  return result;
-}
-
-static void
-yyerror (const char *msg)
-{
-  pstate->parse_error (msg);
-}
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 7bee1f36dc83..53bb8e25212e 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -25,6 +25,7 @@
 #include "language.h"
 #include "varobj.h"
 #include "m2-lang.h"
+#include "m2-exp-parser.h"
 #include "c-lang.h"
 #include "valprint.h"
 #include "gdbarch.h"
@@ -118,6 +119,14 @@ static m2_language m2_language_defn;
 
 /* See language.h.  */
 
+int
+m2_language::parser (struct parser_state *ps) const
+{
+  return m2_parse (ps);
+}
+
+/* See language.h.  */
+
 void
 m2_language::language_arch_info (struct gdbarch *gdbarch,
 				 struct language_arch_info *lai) const
-- 
2.55.0


  parent reply	other threads:[~2026-09-04 17:08 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-04 16:56 [PATCH 00/17] Move C++ support code out of .y files simon.marchi
2026-09-04 16:56 ` [PATCH 01/17] gdb/ada-exp-parser: remove name_info struct simon.marchi
2026-09-04 16:56 ` [PATCH 02/17] gdb: replace parse_type macros with functions simon.marchi
2026-09-04 16:56 ` [PATCH 03/17] gdb: suffix flex/bison output files with -gen.c simon.marchi
2026-09-04 16:56 ` [PATCH 04/17] gdb: move parser output post-processing to a script simon.marchi
2026-09-05  0:38   ` Kevin Buettner
2026-09-05  3:59     ` Simon Marchi
2026-09-04 16:56 ` [PATCH 05/17] gdb: let the parser and lexer generators prefix their symbols simon.marchi
2026-09-04 16:56 ` [PATCH 06/17] gdb: separate cp-name-parser's symbol prefix with an underscore simon.marchi
2026-09-04 16:56 ` [PATCH 07/17] gdb: make $(YACC) and $(FLEX) generate headers simon.marchi
2026-09-04 16:56 ` [PATCH 08/17] gdb: add check for stale build generated files simon.marchi
2026-09-04 16:56 ` [PATCH 09/17] gdb: move cp-name-parser.y's support code to cp-name-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 10/17] gdb: rename LANG-exp.y to LANG-exp-parser.y simon.marchi
2026-09-04 16:56 ` [PATCH 11/17] gdb: move c-exp-parser.y's support code to c-exp-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 12/17] gdb: move ada-exp-parser.y's support code to ada-exp-parser.c simon.marchi
2026-09-05  0:16   ` Kevin Buettner
2026-09-04 16:56 ` [PATCH 13/17] gdb: move d-exp-parser.y's support code to d-exp-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 14/17] gdb: move f-exp-parser.y's support code to f-exp-parser.c simon.marchi
2026-09-04 16:56 ` [PATCH 15/17] gdb: move go-exp-parser.y's support code to go-exp-parser.c simon.marchi
2026-09-04 16:56 ` simon.marchi [this message]
2026-09-05  0:30   ` [PATCH 16/17] gdb: move m2-exp-parser.y's support code to m2-exp-parser.c Kevin Buettner
2026-09-05  4:04     ` Simon Marchi
2026-09-04 16:56 ` [PATCH 17/17] gdb: move p-exp-parser.y's support code to p-exp-parser.c simon.marchi
2026-09-05  0:29   ` Kevin Buettner
2026-09-05  0:50 ` [PATCH 00/17] Move C++ support code out of .y files Kevin Buettner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260904170338.1643894-17-simon.marchi@polymtl.ca \
    --to=simon.marchi@polymtl.ca \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox