src/ir/nfa/init_rules.cc \
src/ir/nfa/make_tags.cc \
src/ir/nfa/nfa.cc \
- src/ir/nfa/nullable.cc \
src/ir/nfa/regexps2nfa.cc \
src/ir/adfa/adfa.cc \
src/ir/adfa/prepare.cc \
src/ir/regexp/encoding/utf16/utf16_regexp.cc \
src/ir/regexp/encoding/utf16/utf16.cc \
src/ir/regexp/encoding/utf16/utf16_range.cc \
+ src/ir/regexp/nullable.cc \
src/ir/regexp/regexp.cc \
src/ir/regexp/split_charset.cc \
src/ir/compile.cc \
src/ir/skeleton/generate_data.cc \
src/ir/skeleton/maxpath.cc \
src/ir/skeleton/skeleton.cc \
- src/ir/skeleton/unreachable_nullable.cc \
+ src/ir/skeleton/unreachable.cc \
src/ir/tag.cc \
src/ir/tagpool.cc \
src/main.cc \
head->action.set_initial (initial_label, head->action.type == Action::SAVE);
warn_undefined_control_flow(*skeleton);
- warn_unreachable_nullable_rules(*skeleton);
+ warn_unreachable(*skeleton);
if (opts->target == opt_t::SKELETON) {
if (output.skeletons.insert (name).second)
}
}
-void Warn::match_empty_string (uint32_t line)
+void Warn::match_empty_string (uint32_t line, const std::string &cond)
{
if (mask[MATCH_EMPTY_STRING] & WARNING)
{
const bool e = mask[MATCH_EMPTY_STRING] & ERROR;
error_accuml |= e;
- warning (names[MATCH_EMPTY_STRING], line, e, "rule matches empty string");
+ warning (names[MATCH_EMPTY_STRING], line, e,
+ "rule %smatches empty string", incond(cond).c_str());
}
}
void condition_order (uint32_t line);
void empty_class (uint32_t line);
- void match_empty_string (uint32_t line);
+ void match_empty_string (uint32_t line, const std::string &cond);
void nondeterministic_tags(uint32_t line, const std::string &cond, const std::string *tagname);
void swapped_range (uint32_t line, uint32_t l, uint32_t u);
void undefined_control_flow (const Skeleton &skel, std::vector<path_t> & paths, bool overflow);
const uint32_t line = output.source.block().line;
const std::string name = make_name(cond, line);
+ warn_nullable(rules, cond);
+
// The original set of code units (charset) might be very large.
// A common trick it is to split charset into disjoint character ranges
// and choose a representative of each range (we choose lower bound).
for (size_t r = 0, t = 0; r < nr; ++r) {
Rule &rule = rules[r];
rule.info = regexps[r]->info;
- rule.nullable = nullable_rule(regexps[r]);
rule.ltag = t;
for (; t < nt && tags[t].rule == r; ++t);
+++ /dev/null
-#include "src/ir/nfa/nfa.h"
-
-namespace re2c {
-
-static bool nullable(const RegExp *re, bool &trail)
-{
- if (trail) {
- return true;
- }
- switch (re->type) {
- case RegExp::NIL:
- case RegExp::ITER:
- return true;
- case RegExp::TAG:
- if (re->tag == NULL) {
- trail = true;
- }
- return true;
- case RegExp::SYM:
- return false;
- case RegExp::ALT:
- return nullable(re->alt.re1, trail)
- || nullable(re->alt.re2, trail);
- case RegExp::CAT:
- return nullable(re->cat.re1, trail)
- && nullable(re->cat.re2, trail);
- default:
- assert(false);
- }
-}
-
-bool nullable_rule(const RegExpRule *rule)
-{
- bool trail = false;
- return nullable(rule->re, trail);
-}
-
-} // namespace re2c
--- /dev/null
+#include "src/conf/opt.h"
+#include "src/ir/regexp/regexp.h"
+#include "src/globals.h"
+
+namespace re2c {
+
+static bool nullable(const RegExp *re, bool &trail)
+{
+ if (trail) {
+ return true;
+ }
+ switch (re->type) {
+ case RegExp::NIL:
+ case RegExp::ITER:
+ return true;
+ case RegExp::TAG:
+ if (re->tag == NULL) {
+ trail = true;
+ }
+ return true;
+ case RegExp::SYM:
+ return false;
+ case RegExp::ALT:
+ return nullable(re->alt.re1, trail)
+ || nullable(re->alt.re2, trail);
+ case RegExp::CAT:
+ return nullable(re->cat.re1, trail)
+ && nullable(re->cat.re2, trail);
+ default:
+ assert(false);
+ }
+}
+
+/*
+ * warn about rules that match empty string
+ * (including rules with nonempty trailing context)
+ * false positives on partially self-shadowed rules like [^]?
+ */
+void warn_nullable(const std::vector<const RegExpRule*> ®exps,
+ const std::string &cond)
+{
+ const size_t nregexps = regexps.size();
+ for (size_t i = 0; i < nregexps; ++i) {
+ const RegExpRule *r = regexps[i];
+ bool trail = false;
+ if (nullable(r->re, trail)) {
+ warn.match_empty_string(r->info->loc.line, cond);
+ }
+ }
+}
+
+} // namespace re2c
const RegExp *repeat(const RegExp *re, uint32_t n);
const RegExp *repeat_from_to(const RegExp *re, uint32_t n, uint32_t m);
const RegExp *repeat_from(const RegExp *re, uint32_t n);
+void warn_nullable(const std::vector<const RegExpRule*> ®exps,
+ const std::string &cond);
} // end namespace re2c
size_t htag;
size_t trail;
size_t tags;
- bool nullable;
std::set<uint32_t> shadow;
bool reachable;
, htag(0)
, trail(Tag::NONE)
, tags(0)
- , nullable(false)
, shadow()
, reachable(false)
{}
uint32_t maxpath(const Skeleton &skel);
void warn_undefined_control_flow(const Skeleton &skel);
void fprint_default_path(FILE *f, const Skeleton &skel, const path_t &p);
-void warn_unreachable_nullable_rules(const Skeleton &skel);
+void warn_unreachable(const Skeleton &skel);
void emit_data(const Skeleton &skel);
void emit_prolog(OutputFile & o);
void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill,
}
}
-void warn_unreachable_nullable_rules(const Skeleton &skel)
+void warn_unreachable(const Skeleton &skel)
{
// calculate reachable rules
const size_t nnodes = skel.nodes_count;
warn.unreachable_rule(skel.cond, rule);
}
}
-
- // warn about nullable rules:
- // - rules that match empty string
- // - rules that match empty strins with nonempty trailing context
- // false positives on partially shadowed (yet reachable) rules, e.g.:
- // [^]?
- for (size_t i = 0; i < nrules; ++i) {
- const Rule &rule = rules[i];
- if (rule.nullable && rule.reachable) {
- warn.match_empty_string(rule.info->loc.line);
- }
- }
}
} // namespace re2c
}
#line 3 "bug116.re"
-re2c: warning: line 3: control flow is undefined for strings that match '[\x0-\x60\x62-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 2: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: control flow is undefined for strings that match '[\x0-\x60\x62-\xFF]', use default rule '*' [-Wundefined-control-flow]
{x;}
}
-re2c: warning: line 2: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 2: rule in condition 'X' matches empty string [-Wmatch-empty-string]
}
#line 7 "condition_02.c.re"
-re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: rule in condition '0' matches empty string [-Wmatch-empty-string]
re2c: warning: line 7: control flow in condition 'r1' is undefined for strings that match '[\x0-\x60\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 7: control flow in condition 'r2' is undefined for strings that match '[\x0-\x61\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
}
#line 7 "condition_02.cg.re"
-re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: rule in condition '0' matches empty string [-Wmatch-empty-string]
re2c: warning: line 7: control flow in condition 'r1' is undefined for strings that match '[\x0-\x60\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 7: control flow in condition 'r2' is undefined for strings that match '[\x0-\x61\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 7: looks like you use hardcoded numbers instead of autogenerated condition names: better add '/*!types:re2c*/' directive or '-t, --type-header' option and don't rely on fixed condition order. [-Wcondition-order]
}
#line 9 "condition_03.cg.re"
-re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: rule in condition '0' matches empty string [-Wmatch-empty-string]
re2c: warning: line 9: control flow in condition 'r1' is undefined for strings that match '[\x0-\x30\x33-\x60\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 9: control flow in condition 'r2' is undefined for strings that match '[\x0-\x30\x33-\x61\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 9: looks like you use hardcoded numbers instead of autogenerated condition names: better add '/*!types:re2c*/' directive or '-t, --type-header' option and don't rely on fixed condition order. [-Wcondition-order]
}
#line 9 "condition_11.cg.re"
-re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: rule in condition '0' matches empty string [-Wmatch-empty-string]
re2c: warning: line 9: control flow in condition 'r1' is undefined for strings that match '[\x0-\x30\x33-\x60\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 9: control flow in condition 'r2' is undefined for strings that match '[\x0-\x30\x33-\x61\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 9: looks like you use hardcoded numbers instead of autogenerated condition names: better add '/*!types:re2c*/' directive or '-t, --type-header' option and don't rely on fixed condition order. [-Wcondition-order]
}
#line 9 "condition_13.cg.re"
-re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: rule in condition '0' matches empty string [-Wmatch-empty-string]
re2c: warning: line 9: control flow in condition 'r1' is undefined for strings that match '[\x0-\x30\x33-\x60\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 9: control flow in condition 'r2' is undefined for strings that match '[\x0-\x30\x33-\x61\x63-\xFF]', use default rule '*' [-Wundefined-control-flow]
re2c: warning: line 9: looks like you use hardcoded numbers instead of autogenerated condition names: better add '/*!types:re2c*/' directive or '-t, --type-header' option and don't rely on fixed condition order. [-Wcondition-order]
{ return DEFAULT-*; }
}
+re2c: warning: line 4: rule in condition 'c3' matches empty string [-Wmatch-empty-string]
re2c: warning: line 4: unreachable rule in condition 'c3' (shadowed by rule at line 5) [-Wunreachable-rules]
#line 7 "input4.--empty-class(match-empty).re"
re2c: warning: line 3: empty character class [-Wempty-character-class]
+re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule (shadowed by rule at line 4) [-Wunreachable-rules]
re2c: warning: line 5: unreachable rule (shadowed by rule at line 4) [-Wunreachable-rules]
#line 7 "input4.re"
re2c: warning: line 3: empty character class [-Wempty-character-class]
+re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule (shadowed by rule at line 4) [-Wunreachable-rules]
re2c: warning: line 5: unreachable rule (shadowed by rule at line 4) [-Wunreachable-rules]
re2c: warning: line 3: empty character class [-Wempty-character-class]
re2c: warning: line 3: empty character class [-Wempty-character-class]
+re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule (shadowed by rule at line 4) [-Wunreachable-rules]
re2c: warning: line 3: empty character class [-Wempty-character-class]
re2c: warning: line 3: empty character class [-Wempty-character-class]
+re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule (shadowed by rule at line 4) [-Wunreachable-rules]
{}
}
+re2c: warning: line 2: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 2: unreachable rule [-Wunreachable-rules]
{}
}
+re2c: warning: line 3: rule in condition 'c1' matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule in condition 'c1' [-Wunreachable-rules]
{}
}
+re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule [-Wunreachable-rules]
{}
}
+re2c: warning: line 3: rule in condition 'c1' matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule in condition 'c1' [-Wunreachable-rules]
{}
}
+re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: unreachable rule [-Wunreachable-rules]
-re2c: error: line 5: tag 'b' is nondeterministic
-re2c: error: line 6: tag 'e' is nondeterministic
-re2c: error: line 8: tag 'c' is nondeterministic
-re2c: error: line 9: tag 'f' is nondeterministic
re2c: warning: line 2: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 3: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 5: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 6: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 8: rule matches empty string [-Wmatch-empty-string]
re2c: warning: line 9: rule matches empty string [-Wmatch-empty-string]
+re2c: error: line 5: tag 'b' is nondeterministic
+re2c: error: line 6: tag 'e' is nondeterministic
+re2c: error: line 8: tag 'c' is nondeterministic
+re2c: error: line 9: tag 'f' is nondeterministic
return 1;
}
}
-re2c: warning: line 44: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 44: rule in condition 'ST_VALUE' matches empty string [-Wmatch-empty-string]