📄 flex.1
字号:
is the file.B lex.yy.c,which contains the scanning routine.B yylex(),a number of tables used by it for matching tokens, and a numberof auxiliary routines and macros. By default,.B yylex()is declared as follows:.nf int yylex() { ... various definitions and the actions in here ... }.fi(If your environment supports function prototypes, then it willbe "int yylex( void )".) This definition may be changed by definingthe "YY_DECL" macro. For example, you could use:.nf #define YY_DECL float lexscan( a, b ) float a, b;.fito give the scanning routine the name.I lexscan,returning a float, and taking two floats as arguments. Note thatif you give arguments to the scanning routine using aK&R-style/non-prototyped function declaration, you must terminatethe definition with a semi-colon (;)..PPWhenever.B yylex()is called, it scans tokens from the global input file.I yyin(which defaults to stdin). It continues until it either reachesan end-of-file (at which point it returns the value 0) orone of its actions executes a.I returnstatement..PPIf the scanner reaches an end-of-file, subsequent calls are undefinedunless either.I yyinis pointed at a new input file (in which case scanning continues fromthat file), or.B yyrestart()is called..B yyrestart()takes one argument, a.B FILE *pointer (which can be nil, if you've set up.B YY_INPUTto scan from a source other than.I yyin),and initializes.I yyinfor scanning from that file. Essentially there is no difference betweenjust assigning.I yyinto a new input file or using.B yyrestart()to do so; the latter is available for compatibility with previous versionsof.I flex,and because it can be used to switch input files in the middle of scanning.It can also be used to throw away the current input buffer, by callingit with an argument of.I yyin;but better is to use.B YY_FLUSH_BUFFER(see above).Note that.B yyrestart()does.I notreset the start condition to.B INITIAL(see Start Conditions, below)..PPIf.B yylex()stops scanning due to executing a.I returnstatement in one of the actions, the scanner may then be called again and itwill resume scanning where it left off..PPBy default (and for purposes of efficiency), the scanner usesblock-reads rather than simple.I getc()calls to read characters from.I yyin.The nature of how it gets its input can be controlled by defining the.B YY_INPUTmacro.YY_INPUT's calling sequence is "YY_INPUT(buf,result,max_size)". Itsaction is to place up to.I max_sizecharacters in the character array.I bufand return in the integer variable.I resulteither thenumber of characters read or the constant YY_NULL (0 on Unix systems)to indicate EOF. The default YY_INPUT reads from theglobal file-pointer "yyin"..PPA sample definition of YY_INPUT (in the definitionssection of the input file):.nf %{ #define YY_INPUT(buf,result,max_size) \\ { \\ int c = getchar(); \\ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \\ } %}.fiThis definition will change the input processing to occurone character at a time..PPWhen the scanner receives an end-of-file indication from YY_INPUT,it then checks the.B yywrap()function. If.B yywrap()returns false (zero), then it is assumed that thefunction has gone ahead and set up.I yyinto point to another input file, and scanning continues. If it returnstrue (non-zero), then the scanner terminates, returning 0 to itscaller. Note that in either case, the start condition remains unchanged;it does.I notrevert to.B INITIAL..PPIf you do not supply your own version of.B yywrap(),then you must either use.B %option noyywrap(in which case the scanner behaves as though.B yywrap()returned 1), or you must link with.B \-lflto obtain the default version of the routine, which always returns 1..PPThree routines are available for scanning from in-memory buffers ratherthan files:.B yy_scan_string(), yy_scan_bytes(),and.B yy_scan_buffer().See the discussion of them below in the section Multiple Input Buffers..PPThe scanner writes its.B ECHOoutput to the.I yyoutglobal (default, stdout), which may be redefined by the user simplyby assigning it to some other.B FILEpointer..SH START CONDITIONS.I flexprovides a mechanism for conditionally activating rules. Any rulewhose pattern is prefixed with "<sc>" will only be active whenthe scanner is in the start condition named "sc". For example,.nf <STRING>[^"]* { /* eat up the string body ... */ ... }.fiwill be active only when the scanner is in the "STRING" startcondition, and.nf <INITIAL,STRING,QUOTE>\\. { /* handle an escape ... */ ... }.fiwill be active only when the current start condition iseither "INITIAL", "STRING", or "QUOTE"..PPStart conditionsare declared in the definitions (first) section of the inputusing unindented lines beginning with either.B %sor.B %xfollowed by a list of names.The former declares.I inclusivestart conditions, the latter.I exclusivestart conditions. A start condition is activated using the.B BEGINaction. Until the next.B BEGINaction is executed, rules with the given startcondition will be active andrules with other start conditions will be inactive.If the start condition is.I inclusive,then rules with no start conditions at all will also be active.If it is.I exclusive,then.I onlyrules qualified with the start condition will be active.A set of rules contingent on the same exclusive start conditiondescribe a scanner which is independent of any of the other rules in the.I flexinput. Because of this,exclusive start conditions make it easy to specify "mini-scanners"which scan portions of the input that are syntactically differentfrom the rest (e.g., comments)..PPIf the distinction between inclusive and exclusive start conditionsis still a little vague, here's a simple example illustrating theconnection between the two. The set of rules:.nf %s example %% <example>foo do_something(); bar something_else();.fiis equivalent to.nf %x example %% <example>foo do_something(); <INITIAL,example>bar something_else();.fiWithout the.B <INITIAL,example>qualifier, the.I barpattern in the second example wouldn't be active (i.e., couldn't match)when in start condition.B example.If we just used.B <example>to qualify.I bar,though, then it would only be active in.B exampleand not in.B INITIAL,while in the first example it's active in both, because in the firstexample the.B examplestartion condition is an.I inclusive.B (%s)start condition..PPAlso note that the special start-condition specifier.B <*>matches every start condition. Thus, the above example could alsohave been written;.nf %x example %% <example>foo do_something(); <*>bar something_else();.fi.PPThe default rule (to.B ECHOany unmatched character) remains active in start conditions. Itis equivalent to:.nf <*>.|\\n ECHO;.fi.PP.B BEGIN(0)returns to the original state where only the rules withno start conditions are active. This state can also bereferred to as the start-condition "INITIAL", so.B BEGIN(INITIAL)is equivalent to.B BEGIN(0).(The parentheses around the start condition name are not required butare considered good style.).PP.B BEGINactions can also be given as indented code at the beginningof the rules section. For example, the following will causethe scanner to enter the "SPECIAL" start condition whenever.B yylex()is called and the global variable.I enter_specialis true:.nf int enter_special; %x SPECIAL %% if ( enter_special ) BEGIN(SPECIAL); <SPECIAL>blahblahblah ...more rules follow....fi.PPTo illustrate the uses of start conditions,here is a scanner which provides two different interpretationsof a string like "123.456". By default it will treat it asthree tokens, the integer "123", a dot ('.'), and the integer "456".But if the string is preceded earlier in the line by the string"expect-floats"it will treat it as a single token, the floating-point number123.456:.nf %{ #include <math.h> %} %s expect %% expect-floats BEGIN(expect); <expect>[0-9]+"."[0-9]+ { printf( "found a float, = %f\\n", atof( yytext ) ); } <expect>\\n { /* that's the end of the line, so * we need another "expect-number" * before we'll recognize any more * numbers */ BEGIN(INITIAL); } [0-9]+ { printf( "found an integer, = %d\\n", atoi( yytext ) ); } "." printf( "found a dot\\n" );.fiHere is a scanner which recognizes (and discards) C comments whilemaintaining a count of the current input line..nf %x comment %% int line_num = 1; "/*" BEGIN(comment); <comment>[^*\\n]* /* eat anything that's not a '*' */ <comment>"*"+[^*/\\n]* /* eat up '*'s not followed by '/'s */ <comment>\\n ++line_num; <comment>"*"+"/" BEGIN(INITIAL);.fiThis scanner goes to a bit of trouble to match as muchtext as possible with each rule. In general, when attempting to writea high-speed scanner try to match as much possible in each rule, asit's a big win..PPNote that start-conditions names are really integer values andcan be stored as such. Thus, the above could be extended in thefollowing fashion:.nf %x comment foo %% int line_num = 1; int comment_caller; "/*" { comment_caller = INITIAL; BEGIN(comment); } ... <foo>"/*" { comment_caller = foo; BEGIN(comment); } <comment>[^*\\n]* /* eat anything that's not a '*' */ <comment>"*"+[^*/\\n]* /* eat up '*'s not followed by '/'s */ <comment>\\n ++line_num; <comment>"*"+"/" BEGIN(comment_caller);.fiFurthermore, you can access the current start condition usingthe integer-valued.B YY_STARTmacro. For example, the above assignments to.I comment_callercould instead be written.nf comment_caller = YY_START;.fiFlex provides.B YYSTATEas an alias for.B YY_START(since that is what's used by AT&T.I lex)..PPNote that start conditions do not have their own name-space; %s's and %x'sdeclare names in the same fashion as #define's..PPFinally, here's an example of how to match C-style quoted strings usingexclusive start conditions, including expanded escape sequences (butnot including checking for a string that's too long):.nf %x str %% char string_buf[MAX_STR_CONST]; char *string_buf_ptr; \\" string_buf_ptr = string_buf; BEGIN(str); <str>\\" { /* saw closing quote - all done */ BEGIN(INITIAL); *string_buf_ptr = '\\0'; /* return string constant token type and * value to parser */ } <str>\\n { /* error - unterminated string constant */ /* generate error message */ } <str>\\\\[0-7]{1,3} { /* octal escape sequence */ int result; (void) sscanf( yytext + 1, "%o", &result ); if ( result > 0xff ) /* error, constant is out-of-bounds */ *string_buf_ptr++ = result; } <str>\\\\[0-9]+ { /* generate error - bad escape sequence; something * like '\\48' or '\\0777777' */ } <str>\\\\n *string_buf_ptr++ = '\\n'; <str>\\\\t *string_buf_ptr++ = '\\t'; <str>\\\\r *string_buf_ptr++ = '\\r'; <str>\\\\b *string_buf_ptr++ = '\\b'; <str>\\\\f *string_buf_ptr++ = '\\f'; <str>\\\\(.|\\n) *string_buf_ptr++ = yytext[1]; <str>[^\\\\\\n\\"]+ { char *yptr = yytext; while ( *yptr ) *string_buf_ptr++ = *yptr++; }.fi.PPOften, such as in some of the examples above, you wind up writing awhole bunch of rules all preceded by the same start condition(s). Flexmakes this a little easier and cleaner by introducing a notion of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -