Skip to content

Commit

Permalink
Fix PR#18855 issue 2. By Duncan Murdoch.
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.r-project.org/R/trunk@87714 00db46b3-68df-0310-9c12-caf00c1e9a41
  • Loading branch information
hornik committed Feb 12, 2025
1 parent 5dad4a9 commit fa73948
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 145 deletions.
3 changes: 3 additions & 0 deletions doc/NEWS.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,9 @@
\item The \code{tools::parseLatex()} parser made several parsing
errors (\PR{18855}).
\item Error messages produced by \code{tools::parseLatex()} are
now more readable (\PR{18855}).
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/library/tools/R/parseLatex.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
# A copy of the GNU General Public License is available at
# https://www.R-project.org/Licenses/

parseLatex <- function(text, filename = deparse1(substitute(text)),
parseLatex <- function(text, filename = "text",
verbose = FALSE, verbatim = c("verbatim", "verbatim*",
"Sinput", "Soutput"),
verb = "\\Sexpr")
{
## the internal function must get some sort of srcfile
srcfile <- srcfilecopy(filename, text, file.mtime(filename))
srcfile <- srcfilecopy(filename, text)
text <- paste(text, collapse="\n")
.External2(C_parseLatex, text, srcfile, verbose, as.character(verbatim), as.character(verb))
}
Expand Down
4 changes: 2 additions & 2 deletions src/library/tools/man/parseLatex.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
characters.
}
\usage{
parseLatex(text, filename = deparse1(substitute(text)),
parseLatex(text, filename = "text",
verbose = FALSE,
verbatim = c("verbatim", "verbatim*",
"Sinput", "Soutput"),
Expand All @@ -29,7 +29,7 @@ latexToUtf8(x)
A character vector containing LaTeX source code.
}
\item{filename}{
A filename to use in syntax error messages.
No longer used.
}
\item{verbose}{
If \code{TRUE}, print debug error messages.
Expand Down
116 changes: 44 additions & 72 deletions src/library/tools/src/gramLatex.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ struct ParseState {

static Rboolean busy = FALSE;
static ParseState parseState;
static char ParseErrorMsg[PARSE_ERROR_SIZE];

#define PRESERVE_SV(x) R_PreserveInMSet((x), parseState.mset)
#define RELEASE_SV(x) R_ReleaseFromMSet((x), parseState.mset)
Expand All @@ -224,7 +225,7 @@ static int mkVerb2(const char *, int);
static int mkVerbEnv(void);
static int mkDollar(int);

static SEXP R_LatexTagSymbol = NULL;
static SEXP LatexTagSymbol = NULL;

#define YYSTYPE SEXP

Expand Down Expand Up @@ -746,9 +747,9 @@ static const yytype_int8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] =
{
0, 183, 183, 184, 185, 188, 189, 190, 191, 192,
193, 195, 196, 198, 199, 200, 201, 202, 203, 204,
205, 207, 211, 215, 219, 221, 223, 224
0, 184, 184, 185, 186, 189, 190, 191, 192, 193,
194, 196, 197, 199, 200, 201, 202, 203, 204, 205,
206, 208, 212, 216, 220, 222, 224, 225
};
#endif

Expand Down Expand Up @@ -2153,7 +2154,7 @@ static SEXP xxenv(SEXP begin, SEXP body, SEXP end, YYLTYPE *lloc)
RELEASE_SV(body);
}
setAttrib(ans, R_SrcrefSymbol, makeSrcref(lloc, parseState.SrcFile));
setAttrib(ans, R_LatexTagSymbol, mkString("ENVIRONMENT"));
setAttrib(ans, LatexTagSymbol, mkString("ENVIRONMENT"));
if (!isNull(end))
RELEASE_SV(end);
#if DEBUGVALS
Expand All @@ -2171,7 +2172,7 @@ static SEXP xxmath(SEXP body, YYLTYPE *lloc, Rboolean display)
PRESERVE_SV(ans = PairToVectorList(CDR(body)));
RELEASE_SV(body);
setAttrib(ans, R_SrcrefSymbol, makeSrcref(lloc, parseState.SrcFile));
setAttrib(ans, R_LatexTagSymbol,
setAttrib(ans, LatexTagSymbol,
mkString(display ? "DISPLAYMATH" : "MATH"));
#if DEBUGVALS
Rprintf(" result: %p\n", ans);
Expand All @@ -2192,7 +2193,7 @@ static SEXP xxblock(SEXP body, YYLTYPE *lloc)
RELEASE_SV(body);
}
setAttrib(ans, R_SrcrefSymbol, makeSrcref(lloc, parseState.SrcFile));
setAttrib(ans, R_LatexTagSymbol, mkString("BLOCK"));
setAttrib(ans, LatexTagSymbol, mkString("BLOCK"));

#if DEBUGVALS
Rprintf(" result: %p\n", ans);
Expand Down Expand Up @@ -2227,7 +2228,7 @@ static void xxsavevalue(SEXP items, YYLTYPE *lloc)
} else {
PRESERVE_SV(parseState.Value = allocVector(VECSXP, 1));
SET_VECTOR_ELT(parseState.Value, 0, ScalarString(mkChar("")));
setAttrib(VECTOR_ELT(parseState.Value, 0), R_LatexTagSymbol, mkString("TEXT"));
setAttrib(VECTOR_ELT(parseState.Value, 0), LatexTagSymbol, mkString("TEXT"));
}
if (!isNull(parseState.Value)) {
setAttrib(parseState.Value, R_ClassSymbol, mkString("LaTeX"));
Expand All @@ -2237,7 +2238,7 @@ static void xxsavevalue(SEXP items, YYLTYPE *lloc)

static SEXP xxtag(SEXP item, int type, YYLTYPE *lloc)
{
setAttrib(item, R_LatexTagSymbol, mkString(yytname[YYTRANSLATE(type)]));
setAttrib(item, LatexTagSymbol, mkString(yytname[YYTRANSLATE(type)]));
setAttrib(item, R_SrcrefSymbol, makeSrcref(lloc, parseState.SrcFile));
return item;
}
Expand Down Expand Up @@ -2278,10 +2279,7 @@ static int xxgetc(void)
prevcols[prevpos] = parseState.xxcolno;

if (c == EOF) return R_EOF;

R_ParseContextLast = (R_ParseContextLast + 1) % PARSE_CONTEXT_SIZE;
R_ParseContext[R_ParseContextLast] = (char) c;


if (c == '\n') {
parseState.xxlineno += 1;
parseState.xxcolno = 1;
Expand All @@ -2293,8 +2291,6 @@ static int xxgetc(void)

if (c == '\t') parseState.xxcolno = ((parseState.xxcolno + 6) & ~7) + 1;

R_ParseContextLine = parseState.xxlineno;

return c;
}

Expand All @@ -2306,12 +2302,6 @@ static int xxungetc(int c)
parseState.xxcolno = prevcols[prevpos];
prevpos = (prevpos + PUSHBACK_BUFSIZE - 1) % PUSHBACK_BUFSIZE;

R_ParseContextLine = parseState.xxlineno;

R_ParseContext[R_ParseContextLast] = '\0';
/* macOS requires us to keep this non-negative */
R_ParseContextLast = (R_ParseContextLast + PARSE_CONTEXT_SIZE - 1)
% PARSE_CONTEXT_SIZE;
if(npush >= PUSHBACK_BUFSIZE - 2) return R_EOF;
pushback[npush++] = c;
return c;
Expand Down Expand Up @@ -2402,18 +2392,9 @@ static void UseState(ParseState *state) {
parseState.prevState = state->prevState;
}

static void InitSymbols(void)
{
if (!R_LatexTagSymbol)
R_LatexTagSymbol = install("latex_tag");
}

static SEXP ParseLatex(ParseStatus *status, SEXP srcfile)
{
InitSymbols();

R_ParseContextLast = 0;
R_ParseContext[0] = '\0';
LatexTagSymbol = install("latex_tag");

parseState.xxInVerbEnv = NULL;

Expand All @@ -2440,6 +2421,9 @@ static SEXP ParseLatex(ParseStatus *status, SEXP srcfile)

RELEASE_SV(parseState.Value);
UNPROTECT(1); /* parseState.mset */

if (*status == PARSE_ERROR)
error("%s", ParseErrorMsg);

return parseState.Value;
}
Expand All @@ -2459,14 +2443,6 @@ static int char_getc(void)
return (c);
}

static
SEXP R_ParseLatex(SEXP text, ParseStatus *status, SEXP srcfile)
{
nextchar_parse = translateCharUTF8(STRING_ELT(text, 0));
ptr_getc = char_getc;
return ParseLatex(status, srcfile);
}

/*----------------------------------------------------------------------------
*
* The Lexical Analyzer:
Expand Down Expand Up @@ -2537,24 +2513,21 @@ static void yyerror(const char *s)
static char const yyshortunexpected[] = "unexpected %s";
static char const yylongunexpected[] = "unexpected %s '%s'";
char *expecting;
char ParseErrorMsg[PARSE_ERROR_SIZE];
SEXP filename;
char ParseErrorFilename[PARSE_ERROR_SIZE];

char ErrorTranslation[PARSE_ERROR_SIZE];
if (!strncmp(s, yyunexpected, sizeof yyunexpected -1)) {
int i, translated = FALSE;
/* Edit the error message */
expecting = strstr(s + sizeof yyunexpected -1, yyexpecting);
if (expecting) *expecting = '\0';
for (i = 0; yytname_translations[i]; i += 2) {
if (!strcmp(s + sizeof yyunexpected - 1, yytname_translations[i])) {
if (yychar < 256)
snprintf(ParseErrorMsg, PARSE_ERROR_SIZE,
if (yychar < 256 || yychar == END_OF_INPUT)
snprintf(ErrorTranslation, sizeof(ErrorTranslation),
_(yyshortunexpected),
i/2 < YYENGLISH ? _(yytname_translations[i+1])
: yytname_translations[i+1]);
else
snprintf(ParseErrorMsg, PARSE_ERROR_SIZE,
snprintf(ErrorTranslation, sizeof(ErrorTranslation),
_(yylongunexpected),
i/2 < YYENGLISH ? _(yytname_translations[i+1])
: yytname_translations[i+1],
Expand All @@ -2564,48 +2537,45 @@ static void yyerror(const char *s)
}
}
if (!translated) {
if (yychar < 256)
snprintf(ParseErrorMsg, PARSE_ERROR_SIZE,
if (yychar < 256 || yychar == END_OF_INPUT)
snprintf(ErrorTranslation, sizeof(ErrorTranslation),
_(yyshortunexpected),
s + sizeof yyunexpected - 1);
else
snprintf(ParseErrorMsg, PARSE_ERROR_SIZE,
snprintf(ErrorTranslation, sizeof(ErrorTranslation),
_(yylongunexpected),
s + sizeof yyunexpected - 1, CHAR(STRING_ELT(yylval, 0)));
}
if (expecting) {
translated = FALSE;
for (i = 0; yytname_translations[i]; i += 2) {
if (!strcmp(expecting + sizeof yyexpecting - 1, yytname_translations[i])) {
strcat(ParseErrorMsg, _(yyexpecting));
strcat(ParseErrorMsg, i/2 < YYENGLISH ? _(yytname_translations[i+1])
: yytname_translations[i+1]);
strncat(ErrorTranslation, _(yyexpecting),
sizeof(ErrorTranslation) - strlen(ErrorTranslation) - 1);
strncat(ErrorTranslation, i/2 < YYENGLISH
? _(yytname_translations[i+1])
: yytname_translations[i+1],
sizeof(ErrorTranslation) - strlen(ErrorTranslation) - 1);
translated = TRUE;
break;
}
}
if (!translated) {
strcat(ParseErrorMsg, _(yyexpecting));
strcat(ParseErrorMsg, expecting + sizeof yyexpecting - 1);
strncat(ErrorTranslation, _(yyexpecting),
sizeof(ErrorTranslation) - strlen(ErrorTranslation) - 1);
strncat(ErrorTranslation, expecting + sizeof yyexpecting - 1,
sizeof(ErrorTranslation) - strlen(ErrorTranslation) - 1);
}
}
} else if (!strncmp(s, yyunknown, sizeof yyunknown-1)) {
snprintf(ParseErrorMsg, PARSE_ERROR_SIZE,
snprintf(ErrorTranslation, sizeof(ErrorTranslation),
"%s '%s'", s, CHAR(STRING_ELT(yylval, 0)));
} else {
snprintf(ParseErrorMsg, PARSE_ERROR_SIZE,"%s", s);
snprintf(ErrorTranslation, sizeof(ErrorTranslation), "%s", s);
}
filename = findVar(install("filename"), parseState.SrcFile);
if (isString(filename) && LENGTH(filename))
strncpy(ParseErrorFilename, CHAR(STRING_ELT(filename, 0)), PARSE_ERROR_SIZE - 1);
else
ParseErrorFilename[0] = '\0';
if (yylloc.first_line != yylloc.last_line)
warning("%s:%d-%d: %s",
ParseErrorFilename, yylloc.first_line, yylloc.last_line, ParseErrorMsg);
else
warning("%s:%d: %s",
ParseErrorFilename, yylloc.first_line, ParseErrorMsg);
snprintf(ParseErrorMsg, sizeof(ParseErrorMsg),
"Parse error at %d:%d: %s", yylloc.first_line, yylloc.first_column,
ErrorTranslation);
}

#define TEXT_PUSH(c) do { \
Expand Down Expand Up @@ -2877,7 +2847,7 @@ static void PopState(void) {
busy = FALSE;
}

/* "do_parseLatex"
/* "parseLatex"
.External2("parseLatex", text, srcfile, verbose, verbatim, verb)
If there is text then that is read and the other arguments are ignored.
Expand All @@ -2894,8 +2864,7 @@ SEXP parseLatex(SEXP call, SEXP op, SEXP args, SEXP env)
yydebug = 1;
#endif

R_ParseError = 0;
R_ParseErrorMsg[0] = '\0';
ParseErrorMsg[0] = '\0';

PushState();

Expand All @@ -2908,10 +2877,13 @@ SEXP parseLatex(SEXP call, SEXP op, SEXP args, SEXP env)
parseState.xxVerbatimList = CAR(args); args = CDR(args);
parseState.xxVerbList = CAR(args);

s = R_ParseLatex(text, &status, source);
nextchar_parse = translateCharUTF8(STRING_ELT(text, 0));
ptr_getc = char_getc;
s = ParseLatex(&status, source);

PopState();

if (status != PARSE_OK) parseError(call, R_ParseError);
if (status != PARSE_OK) error("%s", ParseErrorMsg);

return s;
}
Loading

0 comments on commit fa73948

Please sign in to comment.