]> granicus.if.org Git - flex/commitdiff
Start condition prefixes attempts to adjust to user preferences.
authorJohn Millaway <john43@users.sourceforge.net>
Wed, 14 Aug 2002 00:46:59 +0000 (00:46 +0000)
committerJohn Millaway <john43@users.sourceforge.net>
Wed, 14 Aug 2002 00:46:59 +0000 (00:46 +0000)
flex.texi
flexdef.h
main.c
misc.c

index b6dfea82024e3b83f7d3225a5926b716564947f1..62240111dac8cccf5cddab25787919ecf91426cc 100644 (file)
--- a/flex.texi
+++ b/flex.texi
@@ -1777,8 +1777,20 @@ assignments to @code{comment_caller} could instead be written
 Flex provides @code{YYSTATE} as an alias for @code{YY_START} (since that
 is what's used by AT&T @code{lex}).
 
-Note that start conditions do not have their own name-space; %s's and %x's
-declare names in the same fashion as #define's.
+For historical reasons, start conditions do not have their own
+name-space within the generated scanner. The start condition names are
+unmodified in the generated scanner. However, they are prefixed
+with @samp{yysc_} in the generated header, where @samp{yy} corresponds
+to the appropriate prefix. Thus, @code{%x comment} produces
+@code{#define comment n} in the scanner, and produces
+@code{#define yysc_comment}
+in the header. If you have already prefixed the start condition,
+then flex attempts to respect your design by honoring the prefix.
+Likewise, flex attempts to respect your capitalization convention.
+
+@xref{option-header}. @xref{option-prefix}.
+
+
 
 Finally, here's an example of how to match C-style quoted strings using
 exclusive start conditions, including expanded escape sequences (but
@@ -2392,8 +2404,11 @@ and then exits.
 @anchor{option-header}
 @item --header=FILE
 instructs flex to write a C header to @file{FILE}. This file contains
-function prototypes, extern variables, and macros used by the scanner.
-It is meant to be included in other C files to avoid compiler warnings.
+function prototypes, extern variables, and types used by the scanner.
+Only the external API is exported by the header file. Many macros that
+are usable from within scanner actions are not exported to the header
+file. This is due to namespace problems and the goal of a clean
+external API.
 The @samp{--header} option is not compatible with the @samp{--c++} option,
 since the C++ scanner provides its own header in @file{yyFlexLexer.h}.
 
@@ -2727,13 +2742,14 @@ then the scanner is written to @file{stdout} but its @code{#line}
 directives (see the @samp{-l} option above) refer to the file
 @file{FILE}.
 
+@anchor{option-prefix}
 @item -PPREFIX, --prefix=PREFIX
 changes the default @samp{yy} prefix used by @code{flex} for all
 globally-visible variable and function names to instead be
 @samp{PREFIX}.  For example, @samp{--prefix=foo} changes the name of
 @code{yytext} to @code{footext}.  It also changes the name of the default
-output file from @file{lex.yy.c} to @file{lex.foo.c}.  Here are all of
-the names affected:
+output file from @file{lex.yy.c} to @file{lex.foo.c}.  Here is a partial
+list of the names affected:
 
 @example
 @verbatim
index 0fb12e243802d99401c400cbd6ae1eb9f57dc9bf..a7effb55acf7eafd6405a47abf0ee02c75c2687c 100644 (file)
--- a/flexdef.h
+++ b/flexdef.h
@@ -1078,4 +1078,16 @@ extern jmp_buf flex_main_jmp_buf;
 /* Removes all \n and \r chars from tail of str. returns str. */
 extern char* chomp(char* str);
 
+/* converts str to lowercase. returns str. */
+extern char * strlower (char *str);
+
+/* converts str to lowercase. returns str. */
+extern char * strupper (char *str);
+
+/* guess case preference for str */
+extern int case_preference (const char* str);
+
+/* creates a name-space safe copy of start cond name in buf. returns buf */
+extern char * fix_scname (char * buf, const char * name);
+
 #endif /* not defined FLEXDEF_H */
diff --git a/main.c b/main.c
index 4e47485918ec106a382e44df76391e50d73c94d4..5edbd182dc2f1d44bbacbe1b05972267263e3075 100644 (file)
--- a/main.c
+++ b/main.c
@@ -568,9 +568,8 @@ int exit_status;
 
             /* Print the prefixed start conditions. */
             for (i=1; i <= lastsc; i++)
-                fprintf(header_out, "#define %sSC_%s %d\n",
-                        strcmp(prefix,"yy") ? prefix : "YY",
-                        scname[i], i-1);
+                fprintf(header_out, "#define %s %d\n",
+                        fix_scname(linebuf,scname[i]), i-1);
 
             /* Kill ALL flex-related macros. This is so the user
              * can #include more than one generated header file. */
diff --git a/misc.c b/misc.c
index 5a86a23a6ffd914d38944ac9c4fc104ff658d4a5..2d5c9e78ae4d15dba1a07c38b577961393ab0ee1 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -933,3 +933,105 @@ char* chomp(str)
         *p-- = 0;
     return str;
 }
+
+/* Converts str to lowercase in place. returns str*/
+char * strlower (str)
+    char* str;
+{
+    char * s = str;
+    if (str)
+        for (s=str; *s; s++)
+            *s = tolower(*s);
+    return str;
+}
+
+/* Converts str to uppercase in place. returns str*/
+char * strupper (str)
+    char* str;
+{
+    char * s;
+    if (str)
+        for (s=str; *s; s++)
+            *s = toupper(*s);
+    return str;
+}
+
+/* return < 0 if prefers lowercase
+ * return > 0 if prefers uppercase
+ * return 0 if no preference or it looks like first-letter-capitalization
+ * Similar to strcmp(), the absolute value of the return value is larger
+ * the more characters are upper or lowercase.
+ */
+int case_preference (str)
+    const char* str;
+{
+    int nup=0, nlow=0, first_up=0;
+    const char* s;
+    if (!str)
+        return 0;
+
+    /* find the first upper or lowercase letter */
+    for (s=str; *s; s++){
+        if (!isupper(*s) && !islower(*s))
+            continue;
+        first_up = isupper(*s);
+        break;
+    }
+
+    for (s=str; *s; s++){
+        if (isupper(*s))
+            nup++;
+        if (islower(*s))
+            nlow++;
+    }
+
+    return (first_up && nlow > nup) ? 0 : nup - nlow;
+}
+
+/* Creates a name-space friendly start condition name, safe for
+ * use in the generated header.
+ * buf should be large enough to contain name and prefix.
+ * returns buf
+ */
+char * fix_scname (buf, name)
+    char * buf;
+    const char * name;
+{
+    char * pre;
+    int cn,cp;
+
+    buf[0]= '\0';
+    if (!name)
+        return buf;
+
+    /* we do comparisons in lowercase */
+    pre = copy_string(prefix);
+    strlower(pre);
+    strcpy(buf,name);
+    strlower(buf);
+
+    /* If the user has already prefixed name, then we leave it alone. */
+    if (strncmp(buf,pre,strlen(pre))==0 && strlen(name) > strlen(pre)){
+        strcpy(buf,name);
+        free(pre);
+        return buf;
+    }
+
+    /* Build the new name */
+    sprintf(buf,"%ssc_%s", prefix, name);
+
+    /* Decide whether the user prefers upper or lowercase or neither */
+    cp = case_preference(prefix);
+    cn = case_preference(name);
+
+    if (cn != 0) {
+        /* If it's mostly lowercase... */
+        if (cn < 0 && (0 - cn) >  strlen(name)/2)
+            strlower(buf);
+        else if (cn > 0 && cn > strlen(name)/2)
+            strupper(buf);
+    }
+
+    free(pre);
+    return buf;
+}