+2022-05-24 Paul Eggert <eggert@cs.ucla.edu>
+
+ dfa: new options DFA_STAR_WARN, DFA_PLUS_WARN
+ This lets ‘grep -E '(*a|+b)'’ warn about the * and the +.
+ * lib/dfa.h (DFA_STAR_WARN, DFA_PLUS_WARN): New flags.
+ * lib/dfa.c (lex): Support them.
+
2022-05-23 Paul Eggert <eggert@cs.ucla.edu>
dfa: '\n' is not governed by RE_LIMITED_OPS
goto default_case;
if (backslash != ((dfa->syntax.syntax_bits & RE_BK_PLUS_QM) != 0))
goto normal_char;
- if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lex.laststart)
- goto normal_char;
+ if (dfa->lex.laststart)
+ {
+ if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS))
+ goto default_case;
+ if (dfa->syntax.dfaopts & DFA_PLUS_WARN)
+ dfawarn (_("? at start of expression"));
+ }
return dfa->lex.lasttok = QMARK;
case '*':
if (backslash)
goto normal_char;
- if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lex.laststart)
- goto normal_char;
+ if (dfa->lex.laststart)
+ {
+ if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS))
+ goto default_case;
+ if (dfa->syntax.dfaopts & DFA_STAR_WARN)
+ dfawarn (_("* at start of expression"));
+ }
return dfa->lex.lasttok = STAR;
case '+':
goto default_case;
if (backslash != ((dfa->syntax.syntax_bits & RE_BK_PLUS_QM) != 0))
goto normal_char;
- if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lex.laststart)
- goto normal_char;
+ if (dfa->lex.laststart)
+ {
+ if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS))
+ goto default_case;
+ if (dfa->syntax.dfaopts & DFA_PLUS_WARN)
+ dfawarn (_("+ at start of expression"));
+ }
return dfa->lex.lasttok = PLUS;
case '{':
goto default_case;
if (backslash != ((dfa->syntax.syntax_bits & RE_NO_BK_BRACES) == 0))
goto normal_char;
- if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lex.laststart)
- goto normal_char;
/* Cases:
{M} - exact count
dfa->lex.maxrep * 10 + *p - '0'));
}
}
- if (! ((! backslash || (p != lim && *p++ == '\\'))
+ bool invalid_content
+ = ! ((! backslash || (p != lim && *p++ == '\\'))
&& p != lim && *p++ == '}'
&& 0 <= dfa->lex.minrep
&& (dfa->lex.maxrep < 0
- || dfa->lex.minrep <= dfa->lex.maxrep)))
+ || dfa->lex.minrep <= dfa->lex.maxrep));
+ if (invalid_content
+ && (dfa->syntax.syntax_bits & RE_INVALID_INTERVAL_ORD))
+ goto normal_char;
+ if (dfa->lex.laststart)
{
- if (dfa->syntax.syntax_bits & RE_INVALID_INTERVAL_ORD)
- goto normal_char;
- dfaerror (_("invalid content of \\{\\}"));
+ if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS))
+ goto default_case;
+ if (dfa->syntax.dfaopts & DFA_PLUS_WARN)
+ dfawarn (_("{...} at start of expression"));
}
+ if (invalid_content)
+ dfaerror (_("invalid content of \\{\\}"));
if (RE_DUP_MAX < dfa->lex.maxrep)
dfaerror (_("regular expression too big"));
dfa->lex.ptr = p;
/* Warn about stray backslashes before ordinary characters. */
DFA_STRAY_BACKSLASH_WARN = 1 << 3,
+
+ /* Warn about * appearing out of context at the start of an
+ expression or subexpression. */
+ DFA_STAR_WARN = 1 << 4,
+
+ /* Warn about +, ?, {...} appearing out of context at the start of
+ an expression or subexpression. */
+ DFA_PLUS_WARN = 1 << 5,
};
/* Initialize or reinitialize a DFA. The arguments are: