/* Handling of compiler pragmats.
Copyright (C) 2025 Jose E. Marchesi.
Written 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
. */
#define INCLUDE_MEMORY
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "a68.h"
/* Utility macros useful for parsing pragmat contents. */
#define SKIP_WHITESPACES(P) \
while (ISSPACE (*(P))) (P)++
#define PARSE_WORD(P,W) \
do \
{ \
(W) = (char *) alloca (strlen ((P))); \
size_t i = 0; \
while (ISALPHA (*(P))) \
(W)[i++] = *((P)++); \
(W)[i] = '\0'; \
} while (0)
/* Parse a string denotation and return its value in an allocated buffer in
*STR. It is up to the caller to dispose of the allocated memory.
This function returns a pointer to the character following the string
denotation in P, or P in case of parse error.
In case of parse error *STR is also set to NULL. */
const char *
parse_string_denotation (const char *p, char **str)
{
const char *orig = p;
size_t i = 0;
char *s = (char *) xmalloc (2 * strlen (p));
if (*(p++) != '\"')
goto error;
while (*p != '\0' && *p != '\"')
{
if (*p == '\'' && *(p + 1) == '\"')
{
s[i++] = '\"';
p += 2;
}
else
{
s[i++] = *p;
p++;
}
}
if (*p != '\"')
goto error;
*str = s;
return p + 1;
error:
free (s);
*str = NULL;
return orig;
}
/* PR access MODULE in "filename" PR */
const char *
handle_access_in_pragmat (NODE_T *p, const char *pragmat, size_t pos)
{
const char *beginning = pragmat;
SKIP_WHITESPACES (pragmat);
/* Parse module name. */
char *module;
PARSE_WORD (pragmat, module);
if (*module == '\0')
{
a68_error (p, "invalid pragmat: expected module name after %");
return NULL;
}
SKIP_WHITESPACES (pragmat);
/* Parse "in " */
if (strncmp (pragmat, "in ", 3) != 0)
{
a68_error (p, "invalid pragmat: expected % after module name");
return NULL;
}
pragmat += 3;
SKIP_WHITESPACES (pragmat);
/* Parse a string denotation. */
char *filename;
pragmat = parse_string_denotation (pragmat, &filename);
if (filename == NULL)
{
size_t off = pos + pragmat - beginning;
char *found;
PARSE_WORD (pragmat, found);
a68_error_in_pragmat (p, off,
"in % pragmat, expected string, found Z",
found);
return NULL;
}
/* Add entry in the module files map. */
const char **pmodule = A68_MODULE_FILES->get (module);
if (pmodule != NULL)
{
a68_error_in_pragmat (p, pos + pragmat - beginning,
"module Z cannot appear in multiple % pragmats",
module);
return NULL;
}
SKIP_WHITESPACES (pragmat);
/* Skip closing PR or PRAGMAT. */
if (NPRAGMAT_TYPE (p) == STYLE_I_PRAGMAT_SYMBOL)
pragmat += 2;
else
pragmat += 7;
A68_MODULE_FILES->put (ggc_strdup (module), ggc_strdup (filename));
free (filename);
return pragmat;
}
/* Parse and action on a pragmat. */
void
handle_pragmat (NODE_T *p)
{
const char *pragmat = NPRAGMAT (p);
if (pragmat != NULL
&& (NPRAGMAT_TYPE (p) == STYLE_I_PRAGMAT_SYMBOL
|| NPRAGMAT_TYPE (p) == BOLD_PRAGMAT_SYMBOL))
{
/* Process pragmat commands. */
do
{
SKIP_WHITESPACES (pragmat);
/* Skip PR or PRAGMAT. */
if (NPRAGMAT_TYPE (p) == STYLE_I_PRAGMAT_SYMBOL)
pragmat += 2;
else
pragmat += 7;
SKIP_WHITESPACES (pragmat);
/* Get first word in pragmat and dispatch. */
SKIP_WHITESPACES (pragmat);
char *word = (char *) alloca (strlen (pragmat));
size_t i = 0;
while (ISALPHA (*pragmat) || *pragmat == '\n')
word[i++] = *(pragmat++);
word[i] = '\0';
if (strcmp (word, "access") == 0)
{
pragmat
= handle_access_in_pragmat (p, pragmat, pragmat - NPRAGMAT (p));
if (pragmat == NULL)
break;
}
else if (strcmp (word, "include") == 0)
/* Include pragmats are handled in the scanner. */
return;
else
{
a68_error_in_pragmat (p, pragmat - NPRAGMAT (p),
"unrecognized pragmat Z", word);
break;
}
}
while (*pragmat != '\0');
}
}
/* Entry point: handle all pragmats in the given parse tree. */
void
a68_handle_pragmats (NODE_T *p)
{
for (; p != NO_NODE; FORWARD (p))
{
a68_handle_pragmats (SUB (p));
handle_pragmat (p);
}
}