diff --git a/ChangeLog b/ChangeLog index 966028a86..4186f0fcc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,11 @@ -2004-06-23 Alexandre Duret-Lutz +2004-06-23 Alexandre Duret-Lutz + + * src/ltlvisit/tostring.cc (is_bare_word): New function. + (to_string_visitor::visitor(const atomic_prop*)): Use is_bare_word + to better check which atomic proposition need to be quoted. + * src/ltlparse/ltlscan.ll: Do not allow identifiers starting with F_ + or G_. + * src/ltltest/equals.test, src/ltltest/tostring.test: More tests. * src/tgba/tgbatba.cc (tgba_tba_proxy::format_state): Use bdd_format_accset to print the acceptance condition part of the state. diff --git a/src/ltlparse/ltlscan.ll b/src/ltlparse/ltlscan.ll index d7f020da5..906f2579c 100644 --- a/src/ltlparse/ltlscan.ll +++ b/src/ltlparse/ltlscan.ll @@ -96,10 +96,10 @@ flex_set_buffer(const char* buf) used by a unary operator (F,G,X), unless this letter is followed by a digit in which case we assume it's an ATOMIC_PROP (even though F0 could be seen as Ffalse, we - don't). + don't, because Ffalse is never used in practice). */ [a-zA-EH-WYZ_][a-zA-Z0-9_]* | -[FGX][0-9_][a-zA-Z0-9_]* | +[FGX][0-9][a-zA-Z0-9_]* | /* However if we have just parsed an atomic proposition, then we are not expecting another atomic proposition, so we can be stricter diff --git a/src/ltltest/equals.test b/src/ltltest/equals.test index 858bb60fe..80e040b27 100755 --- a/src/ltltest/equals.test +++ b/src/ltltest/equals.test @@ -57,3 +57,6 @@ run 1 ./equals 'a & b & (c |(f U g)| e)' \ # Precedence run 0 ./equals 'a & b ^ c | d' 'd | c ^ b & a' + +# Corner cases parsing +run 0 ./equals 'FFG__GFF' 'F(F(G("__GFF")))' diff --git a/src/ltltest/tostring.test b/src/ltltest/tostring.test index ed1828808..453ad9c12 100755 --- a/src/ltltest/tostring.test +++ b/src/ltltest/tostring.test @@ -51,3 +51,6 @@ run 0 ./tostring 'G"TruE"' run 0 ./tostring 'FFALSE' run 0 ./tostring 'GTruE' run 0 ./tostring 'p=0UFXp=1' +run 0 ./tostring 'GF"\GF"' +run 0 ./tostring 'GF"foo bar"' +run 0 ./tostring 'FFG__GFF' diff --git a/src/ltlvisit/tostring.cc b/src/ltlvisit/tostring.cc index 9f6d6e3db..876f1290f 100644 --- a/src/ltlvisit/tostring.cc +++ b/src/ltlvisit/tostring.cc @@ -21,6 +21,7 @@ #include #include +#include #include "tostring.hh" #include "ltlast/visitor.hh" #include "ltlast/allnodes.hh" @@ -31,6 +32,27 @@ namespace spot namespace ltl { + static bool + is_bare_word(const char* str) + { + // Bare words cannot be empty, start with the letter of a unary + // operator, or be the name of an existing constant. Also they + // should start with an letter. + if (!*str + || *str == 'F' + || *str == 'G' + || *str == 'X' + || !(isalpha(*str) || *str == '_') + || !strcasecmp(str, "true") + || !strcasecmp(str, "false")) + return false; + // The remaining of the word must be alphanumeric. + while (*++str) + if (!(isalnum(*str) || *str == '_')) + return false; + return true; + } + class to_string_visitor : public const_visitor { public: @@ -48,9 +70,7 @@ namespace spot visit(const atomic_prop* ap) { std::string str = ap->name(); - if (str[0] == 'F' || str[0] == 'G' || str[0] == 'X' - || !strcasecmp(str.c_str(), "true") - || !strcasecmp(str.c_str(), "false")) + if (!is_bare_word(str.c_str())) { os_ << '"' << str << '"'; }