⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flex.1

📁 flex编译器的源代码
💻 1
📖 第 1 页 / 共 5 页
字号:
so flex defines
.B [:blank:]
as a blank or a tab.
.PP
For example, the following character classes are all equivalent:
.nf

    [[:alnum:]]
    [[:alpha:][:digit:]
    [[:alpha:]0-9]
    [a-zA-Z0-9]

.fi
If your scanner is case-insensitive (the
.B \-i
flag), then
.B [:upper:]
and
.B [:lower:]
are equivalent to
.B [:alpha:].
.PP
Some notes on patterns:
.IP -
A negated character class such as the example "[^A-Z]"
above
.I will match a newline
unless "\\n" (or an equivalent escape sequence) is one of the
characters explicitly present in the negated character class
(e.g., "[^A-Z\\n]").  This is unlike how many other regular
expression tools treat negated character classes, but unfortunately
the inconsistency is historically entrenched.
Matching newlines means that a pattern like [^"]* can match the entire
input unless there's another quote in the input.
.IP -
A rule can have at most one instance of trailing context (the '/' operator
or the '$' operator).  The start condition, '^', and "<<EOF>>" patterns
can only occur at the beginning of a pattern, and, as well as with '/' and '$',
cannot be grouped inside parentheses.  A '^' which does not occur at
the beginning of a rule or a '$' which does not occur at the end of
a rule loses its special properties and is treated as a normal character.
.IP
The following are illegal:
.nf

    foo/bar$
    <sc1>foo<sc2>bar

.fi
Note that the first of these, can be written "foo/bar\\n".
.IP
The following will result in '$' or '^' being treated as a normal character:
.nf

    foo|(bar$)
    foo|^bar

.fi
If what's wanted is a "foo" or a bar-followed-by-a-newline, the following
could be used (the special '|' action is explained below):
.nf

    foo      |
    bar$     /* action goes here */

.fi
A similar trick will work for matching a foo or a
bar-at-the-beginning-of-a-line.
.SH HOW THE INPUT IS MATCHED
When the generated scanner is run, it analyzes its input looking
for strings which match any of its patterns.  If it finds more than
one match, it takes the one matching the most text (for trailing
context rules, this includes the length of the trailing part, even
though it will then be returned to the input).  If it finds two
or more matches of the same length, the
rule listed first in the
.I flex
input file is chosen.
.PP
Once the match is determined, the text corresponding to the match
(called the
.I token)
is made available in the global character pointer
.B yytext,
and its length in the global integer
.B yyleng.
The
.I action
corresponding to the matched pattern is then executed (a more
detailed description of actions follows), and then the remaining
input is scanned for another match.
.PP
If no match is found, then the
.I default rule
is executed: the next character in the input is considered matched and
copied to the standard output.  Thus, the simplest legal
.I flex
input is:
.nf

    %%

.fi
which generates a scanner that simply copies its input (one character
at a time) to its output.
.PP
Note that
.B yytext
can be defined in two different ways: either as a character
.I pointer
or as a character
.I array.
You can control which definition
.I flex
uses by including one of the special directives
.B %pointer
or
.B %array
in the first (definitions) section of your flex input.  The default is
.B %pointer,
unless you use the
.B -l
lex compatibility option, in which case
.B yytext
will be an array.
The advantage of using
.B %pointer
is substantially faster scanning and no buffer overflow when matching
very large tokens (unless you run out of dynamic memory).  The disadvantage
is that you are restricted in how your actions can modify
.B yytext
(see the next section), and calls to the
.B unput()
function destroys the present contents of
.B yytext,
which can be a considerable porting headache when moving between different
.I lex
versions.
.PP
The advantage of
.B %array
is that you can then modify
.B yytext
to your heart's content, and calls to
.B unput()
do not destroy
.B yytext
(see below).  Furthermore, existing
.I lex
programs sometimes access
.B yytext
externally using declarations of the form:
.nf
    extern char yytext[];
.fi
This definition is erroneous when used with
.B %pointer,
but correct for
.B %array.
.PP
.B %array
defines
.B yytext
to be an array of
.B YYLMAX
characters, which defaults to a fairly large value.  You can change
the size by simply #define'ing
.B YYLMAX
to a different value in the first section of your
.I flex
input.  As mentioned above, with
.B %pointer
yytext grows dynamically to accommodate large tokens.  While this means your
.B %pointer
scanner can accommodate very large tokens (such as matching entire blocks
of comments), bear in mind that each time the scanner must resize
.B yytext
it also must rescan the entire token from the beginning, so matching such
tokens can prove slow.
.B yytext
presently does
.I not
dynamically grow if a call to
.B unput()
results in too much text being pushed back; instead, a run-time error results.
.PP
Also note that you cannot use
.B %array
with C++ scanner classes
(the
.B c++
option; see below).
.SH ACTIONS
Each pattern in a rule has a corresponding action, which can be any
arbitrary C statement.  The pattern ends at the first non-escaped
whitespace character; the remainder of the line is its action.  If the
action is empty, then when the pattern is matched the input token
is simply discarded.  For example, here is the specification for a program
which deletes all occurrences of "zap me" from its input:
.nf

    %%
    "zap me"

.fi
(It will copy all other characters in the input to the output since
they will be matched by the default rule.)
.PP
Here is a program which compresses multiple blanks and tabs down to
a single blank, and throws away whitespace found at the end of a line:
.nf

    %%
    [ \\t]+        putchar( ' ' );
    [ \\t]+$       /* ignore this token */

.fi
.PP
If the action contains a '{', then the action spans till the balancing '}'
is found, and the action may cross multiple lines.
.I flex 
knows about C strings and comments and won't be fooled by braces found
within them, but also allows actions to begin with
.B %{
and will consider the action to be all the text up to the next
.B %}
(regardless of ordinary braces inside the action).
.PP
An action consisting solely of a vertical bar ('|') means "same as
the action for the next rule."  See below for an illustration.
.PP
Actions can include arbitrary C code, including
.B return
statements to return a value to whatever routine called
.B yylex().
Each time
.B yylex()
is called it continues processing tokens from where it last left
off until it either reaches
the end of the file or executes a return.
.PP
Actions are free to modify
.B yytext
except for lengthening it (adding
characters to its end--these will overwrite later characters in the
input stream).  This however does not apply when using
.B %array
(see above); in that case,
.B yytext
may be freely modified in any way.
.PP
Actions are free to modify
.B yyleng
except they should not do so if the action also includes use of
.B yymore()
(see below).
.PP
There are a number of special directives which can be included within
an action:
.IP -
.B ECHO
copies yytext to the scanner's output.
.IP -
.B BEGIN
followed by the name of a start condition places the scanner in the
corresponding start condition (see below).
.IP -
.B REJECT
directs the scanner to proceed on to the "second best" rule which matched the
input (or a prefix of the input).  The rule is chosen as described
above in "How the Input is Matched", and
.B yytext
and
.B yyleng
set up appropriately.
It may either be one which matched as much text
as the originally chosen rule but came later in the
.I flex
input file, or one which matched less text.
For example, the following will both count the
words in the input and call the routine special() whenever "frob" is seen:
.nf

            int word_count = 0;
    %%

    frob        special(); REJECT;
    [^ \\t\\n]+   ++word_count;

.fi
Without the
.B REJECT,
any "frob"'s in the input would not be counted as words, since the
scanner normally executes only one action per token.
Multiple
.B REJECT's
are allowed, each one finding the next best choice to the currently
active rule.  For example, when the following scanner scans the token
"abcd", it will write "abcdabcaba" to the output:
.nf

    %%
    a        |
    ab       |
    abc      |
    abcd     ECHO; REJECT;
    .|\\n     /* eat up any unmatched character */

.fi
(The first three rules share the fourth's action since they use
the special '|' action.)
.B REJECT
is a particularly expensive feature in terms of scanner performance;
if it is used in
.I any
of the scanner's actions it will slow down
.I all
of the scanner's matching.  Furthermore,
.B REJECT
cannot be used with the
.I -Cf
or
.I -CF
options (see below).
.IP
Note also that unlike the other special actions,
.B REJECT
is a
.I branch;
code immediately following it in the action will
.I not
be executed.
.IP -
.B yymore()
tells the scanner that the next time it matches a rule, the corresponding
token should be
.I appended
onto the current value of
.B yytext
rather than replacing it.  For example, given the input "mega-kludge"
the following will write "mega-mega-kludge" to the output:
.nf

    %%
    mega-    ECHO; yymore();
    kludge   ECHO;

.fi
First "mega-" is matched and echoed to the output.  Then "kludge"
is matched, but the previous "mega-" is still hanging around at the
beginning of
.B yytext
so the
.B ECHO
for the "kludge" rule will actually write "mega-kludge".
.PP
Two notes regarding use of
.B yymore().
First,
.B yymore()
depends on the value of
.I yyleng
correctly reflecting the size of the current token, so you must not
modify
.I yyleng
if you are using
.B yymore().
Second, the presence of
.B yymore()
in the scanner's action entails a minor performance penalty in the
scanner's matching speed.
.IP -
.B yyless(n)
returns all but the first
.I n
characters of the current token back to the input stream, where they
will be rescanned when the scanner looks for the next match.
.B yytext
and
.B yyleng
are adjusted appropriately (e.g.,
.B yyleng
will now be equal to
.I n
).  For example, on the input "foobar" the following will write out
"foobarbar":
.nf

    %%
    foobar    ECHO; yyless(3);
    [a-z]+    ECHO;

.fi
An argument of 0 to
.B yyless
will cause the entire current input string to be scanned again.  Unless you've
changed how the scanner will subsequently process its input (using
.B BEGIN,
for example), this will result in an endless loop.
.PP
Note that
.B yyless
is a macro and can only be used in the flex input file, not from
other source files.
.IP -
.B unput(c)
puts the character
.I c
back onto the input stream.  It will be the next character scanned.
The following action will take the current token and cause it
to be rescanned enclosed in parentheses.
.nf

    {
    int i;
    /* Copy yytext because unput() trashes yytext */
    char *yycopy = strdup( yytext );
    unput( ')' );
    for ( i = yyleng - 1; i >= 0; --i )
        unput( yycopy[i] );
    unput( '(' );
    free( yycopy );
    }

.fi
Note that since each
.B unput()
puts the given character back at the
.I beginning
of the input stream, pushing back strings must be done back-to-front.
.PP
An important potential problem when using
.B unput()
is that if you are using
.B %pointer
(the default), a call to
.B unput()
.I destroys
the contents of
.I yytext,
starting with its rightmost character and devouring one character to
the left with each call.  If you need the value of yytext preserved
after a call to
.B unput()
(as in the above example),
you must either first copy it elsewhere, or build your scanner using
.B %array
instead (see How The Input Is Matched).
.PP
Finally, note that you cannot put back
.B EOF
to attempt to mark the input stream with an end-of-file.
.IP -
.B input()
reads the next character from the input stream.  For example,
the following is one way to eat up C comments:
.nf

    %%
    "/*"        {
                register int c;

                for ( ; ; )
                    {
                    while ( (c = input()) != '*' &&
                            c != EOF )
                        ;    /* eat up text of comment */

                    if ( c == '*' )
                        {
                        while ( (c = input()) == '*' )
                            ;
                        if ( c == '/' )
                            break;    /* found the end */
                        }

                    if ( c == EOF )
                        {
                        error( "EOF in comment" );
                        break;
                        }
                    }
                }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -