home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / flex2.3 / part08 / flexdoc.1.02 next >
Encoding:
Text File  |  1990-10-10  |  15.2 KB  |  580 lines

  1. Another area where the user can increase a scanner's performance
  2. (and one that's easier to implement) arises from the fact that
  3. the longer the tokens matched, the faster the scanner will run.
  4. This is because with long tokens the processing of most input
  5. characters takes place in the (short) inner scanning loop, and
  6. does not often have to go through the additional work of setting up
  7. the scanning environment (e.g.,
  8. .B yytext)
  9. for the action.  Recall the scanner for C comments:
  10. .nf
  11.  
  12.     %x comment
  13.     %%
  14.             int line_num = 1;
  15.  
  16.     "/*"         BEGIN(comment);
  17.  
  18.     <comment>[^*\\n]*
  19.     <comment>"*"+[^*/\\n]*
  20.     <comment>\\n             ++line_num;
  21.     <comment>"*"+"/"        BEGIN(INITIAL);
  22.  
  23. .fi
  24. This could be sped up by writing it as:
  25. .nf
  26.  
  27.     %x comment
  28.     %%
  29.             int line_num = 1;
  30.  
  31.     "/*"         BEGIN(comment);
  32.  
  33.     <comment>[^*\\n]*
  34.     <comment>[^*\\n]*\\n      ++line_num;
  35.     <comment>"*"+[^*/\\n]*
  36.     <comment>"*"+[^*/\\n]*\\n ++line_num;
  37.     <comment>"*"+"/"        BEGIN(INITIAL);
  38.  
  39. .fi
  40. Now instead of each newline requiring the processing of another
  41. action, recognizing the newlines is "distributed" over the other rules
  42. to keep the matched text as long as possible.  Note that
  43. .I adding
  44. rules does
  45. .I not
  46. slow down the scanner!  The speed of the scanner is independent
  47. of the number of rules or (modulo the considerations given at the
  48. beginning of this section) how complicated the rules are with
  49. regard to operators such as '*' and '|'.
  50. .LP
  51. A final example in speeding up a scanner: suppose you want to scan
  52. through a file containing identifiers and keywords, one per line
  53. and with no other extraneous characters, and recognize all the
  54. keywords.  A natural first approach is:
  55. .nf
  56.  
  57.     %%
  58.     asm      |
  59.     auto     |
  60.     break    |
  61.     ... etc ...
  62.     volatile |
  63.     while    /* it's a keyword */
  64.  
  65.     .|\\n     /* it's not a keyword */
  66.  
  67. .fi
  68. To eliminate the back-tracking, introduce a catch-all rule:
  69. .nf
  70.  
  71.     %%
  72.     asm      |
  73.     auto     |
  74.     break    |
  75.     ... etc ...
  76.     volatile |
  77.     while    /* it's a keyword */
  78.  
  79.     [a-z]+   |
  80.     .|\\n     /* it's not a keyword */
  81.  
  82. .fi
  83. Now, if it's guaranteed that there's exactly one word per line,
  84. then we can reduce the total number of matches by a half by
  85. merging in the recognition of newlines with that of the other
  86. tokens:
  87. .nf
  88.  
  89.     %%
  90.     asm\\n    |
  91.     auto\\n   |
  92.     break\\n  |
  93.     ... etc ...
  94.     volatile\\n |
  95.     while\\n  /* it's a keyword */
  96.  
  97.     [a-z]+\\n |
  98.     .|\\n     /* it's not a keyword */
  99.  
  100. .fi
  101. One has to be careful here, as we have now reintroduced backtracking
  102. into the scanner.  In particular, while
  103. .I we
  104. know that there will never be any characters in the input stream
  105. other than letters or newlines,
  106. .I flex
  107. can't figure this out, and it will plan for possibly needing backtracking
  108. when it has scanned a token like "auto" and then the next character
  109. is something other than a newline or a letter.  Previously it would
  110. then just match the "auto" rule and be done, but now it has no "auto"
  111. rule, only a "auto\\n" rule.  To eliminate the possibility of backtracking,
  112. we could either duplicate all rules but without final newlines, or,
  113. since we never expect to encounter such an input and therefore don't
  114. how it's classified, we can introduce one more catch-all rule, this
  115. one which doesn't include a newline:
  116. .nf
  117.  
  118.     %%
  119.     asm\\n    |
  120.     auto\\n   |
  121.     break\\n  |
  122.     ... etc ...
  123.     volatile\\n |
  124.     while\\n  /* it's a keyword */
  125.  
  126.     [a-z]+\\n |
  127.     [a-z]+   |
  128.     .|\\n     /* it's not a keyword */
  129.  
  130. .fi
  131. Compiled with
  132. .B -Cf,
  133. this is about as fast as one can get a
  134. .I flex 
  135. scanner to go for this particular problem.
  136. .LP
  137. A final note:
  138. .I flex
  139. is slow when matching NUL's, particularly when a token contains
  140. multiple NUL's.
  141. It's best to write rules which match
  142. .I short
  143. amounts of text if it's anticipated that the text will often include NUL's.
  144. .SH INCOMPATIBILITIES WITH LEX AND POSIX
  145. .I flex
  146. is a rewrite of the Unix
  147. .I lex
  148. tool (the two implementations do not share any code, though),
  149. with some extensions and incompatibilities, both of which
  150. are of concern to those who wish to write scanners acceptable
  151. to either implementation.  At present, the POSIX
  152. .I lex
  153. draft is
  154. very close to the original
  155. .I lex
  156. implementation, so some of these
  157. incompatibilities are also in conflict with the POSIX draft.  But
  158. the intent is that except as noted below,
  159. .I flex
  160. as it presently stands will
  161. ultimately be POSIX conformant (i.e., that those areas of conflict with
  162. the POSIX draft will be resolved in
  163. .I flex's
  164. favor).  Please bear in
  165. mind that all the comments which follow are with regard to the POSIX
  166. .I draft
  167. standard of Summer 1989, and not the final document (or subsequent
  168. drafts); they are included so
  169. .I flex
  170. users can be aware of the standardization issues and those areas where
  171. .I flex
  172. may in the near future undergo changes incompatible with
  173. its current definition.
  174. .LP
  175. .I flex
  176. is fully compatible with
  177. .I lex
  178. with the following exceptions:
  179. .IP -
  180. The undocumented
  181. .I lex
  182. scanner internal variable
  183. .B yylineno
  184. is not supported.  It is difficult to support this option efficiently,
  185. since it requires examining every character scanned and reexamining
  186. the characters when the scanner backs up.
  187. Things get more complicated when the end of buffer or file is reached or a
  188. NUL is scanned (since the scan must then be restarted with the proper line
  189. number count), or the user uses the yyless(), unput(), or REJECT actions,
  190. or the multiple input buffer functions.
  191. .IP
  192. The fix is to add rules which, upon seeing a newline, increment
  193. yylineno.  This is usually an easy process, though it can be a drag if some
  194. of the patterns can match multiple newlines along with other characters.
  195. .IP
  196. yylineno is not part of the POSIX draft.
  197. .IP -
  198. The
  199. .B input()
  200. routine is not redefinable, though it may be called to read characters
  201. following whatever has been matched by a rule.  If
  202. .B input()
  203. encounters an end-of-file the normal
  204. .B yywrap()
  205. processing is done.  A ``real'' end-of-file is returned by
  206. .B input()
  207. as
  208. .I EOF.
  209. .IP
  210. Input is instead controlled by redefining the
  211. .B YY_INPUT
  212. macro.
  213. .IP
  214. The
  215. .I flex
  216. restriction that
  217. .B input()
  218. cannot be redefined is in accordance with the POSIX draft, but
  219. .B YY_INPUT
  220. has not yet been accepted into the draft (and probably won't; it looks
  221. like the draft will simply not specify any way of controlling the
  222. scanner's input other than by making an initial assignment to
  223. .I yyin).
  224. .IP -
  225. .I flex
  226. scanners do not use stdio for input.  Because of this, when writing an
  227. interactive scanner one must explicitly call fflush() on the
  228. stream associated with the terminal after writing out a prompt.
  229. With
  230. .I lex
  231. such writes are automatically flushed since
  232. .I lex
  233. scanners use
  234. .B getchar()
  235. for their input.  Also, when writing interactive scanners with
  236. .I flex,
  237. the
  238. .B -I
  239. flag must be used.
  240. .IP -
  241. .I flex
  242. scanners are not as reentrant as
  243. .I lex
  244. scanners.  In particular, if you have an interactive scanner and
  245. an interrupt handler which long-jumps out of the scanner, and
  246. the scanner is subsequently called again, you may get the following
  247. message:
  248. .nf
  249.  
  250.     fatal flex scanner internal error--end of buffer missed
  251.  
  252. .fi
  253. To reenter the scanner, first use
  254. .nf
  255.  
  256.     yyrestart( yyin );
  257.  
  258. .fi
  259. .IP -
  260. .B output()
  261. is not supported.
  262. Output from the
  263. .B ECHO
  264. macro is done to the file-pointer
  265. .I yyout
  266. (default
  267. .I stdout).
  268. .IP
  269. The POSIX draft mentions that an
  270. .B output()
  271. routine exists but currently gives no details as to what it does.
  272. .IP -
  273. .I lex
  274. does not support exclusive start conditions (%x), though they
  275. are in the current POSIX draft.
  276. .IP -
  277. When definitions are expanded,
  278. .I flex
  279. encloses them in parentheses.
  280. With lex, the following:
  281. .nf
  282.  
  283.     NAME    [A-Z][A-Z0-9]*
  284.     %%
  285.     foo{NAME}?      printf( "Found it\\n" );
  286.     %%
  287.  
  288. .fi
  289. will not match the string "foo" because when the macro
  290. is expanded the rule is equivalent to "foo[A-Z][A-Z0-9]*?"
  291. and the precedence is such that the '?' is associated with
  292. "[A-Z0-9]*".  With
  293. .I flex,
  294. the rule will be expanded to
  295. "foo([A-Z][A-Z0-9]*)?" and so the string "foo" will match.
  296. Note that because of this, the
  297. .B ^, $, <s>, /,
  298. and
  299. .B <<EOF>>
  300. operators cannot be used in a
  301. .I flex
  302. definition.
  303. .IP
  304. The POSIX draft interpretation is the same as
  305. .I flex's.
  306. .IP -
  307. To specify a character class which matches anything but a left bracket (']'),
  308. in
  309. .I lex
  310. one can use "[^]]" but with
  311. .I flex
  312. one must use "[^\\]]".  The latter works with
  313. .I lex,
  314. too.
  315. .IP -
  316. The
  317. .I lex
  318. .B %r
  319. (generate a Ratfor scanner) option is not supported.  It is not part
  320. of the POSIX draft.
  321. .IP -
  322. If you are providing your own yywrap() routine, you must include a
  323. "#undef yywrap" in the definitions section (section 1).  Note that
  324. the "#undef" will have to be enclosed in %{}'s.
  325. .IP
  326. The POSIX draft
  327. specifies that yywrap() is a function and this is very unlikely to change; so
  328. .I flex users are warned
  329. that
  330. .B yywrap()
  331. is likely to be changed to a function in the near future.
  332. .IP -
  333. After a call to
  334. .B unput(),
  335. .I yytext
  336. and
  337. .I yyleng
  338. are undefined until the next token is matched.  This is not the case with
  339. .I lex
  340. or the present POSIX draft.
  341. .IP -
  342. The precedence of the
  343. .B {}
  344. (numeric range) operator is different.
  345. .I lex
  346. interprets "abc{1,3}" as "match one, two, or
  347. three occurrences of 'abc'", whereas
  348. .I flex
  349. interprets it as "match 'ab'
  350. followed by one, two, or three occurrences of 'c'".  The latter is
  351. in agreement with the current POSIX draft.
  352. .IP -
  353. The precedence of the
  354. .B ^
  355. operator is different.
  356. .I lex
  357. interprets "^foo|bar" as "match either 'foo' at the beginning of a line,
  358. or 'bar' anywhere", whereas
  359. .I flex
  360. interprets it as "match either 'foo' or 'bar' if they come at the beginning
  361. of a line".  The latter is in agreement with the current POSIX draft.
  362. .IP -
  363. To refer to yytext outside of the scanner source file,
  364. the correct definition with
  365. .I flex
  366. is "extern char *yytext" rather than "extern char yytext[]".
  367. This is contrary to the current POSIX draft but a point on which
  368. .I flex
  369. will not be changing, as the array representation entails a
  370. serious performance penalty.  It is hoped that the POSIX draft will
  371. be emended to support the
  372. .I flex
  373. variety of declaration (as this is a fairly painless change to
  374. require of
  375. .I lex
  376. users).
  377. .IP -
  378. .I yyin
  379. is
  380. .I initialized
  381. by
  382. .I lex
  383. to be
  384. .I stdin;
  385. .I flex,
  386. on the other hand,
  387. initializes
  388. .I yyin
  389. to NULL
  390. and then
  391. .I assigns
  392. it to
  393. .I stdin
  394. the first time the scanner is called, providing
  395. .I yyin
  396. has not already been assigned to a non-NULL value.  The difference is
  397. subtle, but the net effect is that with
  398. .I flex
  399. scanners,
  400. .I yyin
  401. does not have a valid value until the scanner has been called.
  402. .IP -
  403. The special table-size declarations such as
  404. .B %a
  405. supported by
  406. .I lex
  407. are not required by
  408. .I flex
  409. scanners;
  410. .I flex
  411. ignores them.
  412. .IP -
  413. The name
  414. .bd
  415. FLEX_SCANNER
  416. is #define'd so scanners may be written for use with either
  417. .I flex
  418. or
  419. .I lex.
  420. .LP
  421. The following
  422. .I flex
  423. features are not included in
  424. .I lex
  425. or the POSIX draft standard:
  426. .nf
  427.  
  428.     yyterminate()
  429.     <<EOF>>
  430.     YY_DECL
  431.     #line directives
  432.     %{}'s around actions
  433.     yyrestart()
  434.     comments beginning with '#' (deprecated)
  435.     multiple actions on a line
  436.  
  437. .fi
  438. This last feature refers to the fact that with
  439. .I flex
  440. you can put multiple actions on the same line, separated with
  441. semi-colons, while with
  442. .I lex,
  443. the following
  444. .nf
  445.  
  446.     foo    handle_foo(); ++num_foos_seen;
  447.  
  448. .fi
  449. is (rather surprisingly) truncated to
  450. .nf
  451.  
  452.     foo    handle_foo();
  453.  
  454. .fi
  455. .I flex
  456. does not truncate the action.  Actions that are not enclosed in
  457. braces are simply terminated at the end of the line.
  458. .SH DIAGNOSTICS
  459. .I reject_used_but_not_detected undefined
  460. or
  461. .I yymore_used_but_not_detected undefined -
  462. These errors can occur at compile time.  They indicate that the
  463. scanner uses
  464. .B REJECT
  465. or
  466. .B yymore()
  467. but that
  468. .I flex
  469. failed to notice the fact, meaning that
  470. .I flex
  471. scanned the first two sections looking for occurrences of these actions
  472. and failed to find any, but somehow you snuck some in (via a #include
  473. file, for example).  Make an explicit reference to the action in your
  474. .I flex
  475. input file.  (Note that previously
  476. .I flex
  477. supported a
  478. .B %used/%unused
  479. mechanism for dealing with this problem; this feature is still supported
  480. but now deprecated, and will go away soon unless the author hears from
  481. people who can argue compellingly that they need it.)
  482. .LP
  483. .I flex scanner jammed -
  484. a scanner compiled with
  485. .B -s
  486. has encountered an input string which wasn't matched by
  487. any of its rules.
  488. .LP
  489. .I flex input buffer overflowed -
  490. a scanner rule matched a string long enough to overflow the
  491. scanner's internal input buffer (16K bytes by default - controlled by
  492. .B YY_BUF_SIZE
  493. in "flex.skel".  Note that to redefine this macro, you must first
  494. .B #undefine
  495. it).
  496. .LP
  497. .I scanner requires -8 flag -
  498. Your scanner specification includes recognizing 8-bit characters and
  499. you did not specify the -8 flag (and your site has not installed flex
  500. with -8 as the default).
  501. .LP
  502. .I
  503. fatal flex scanner internal error--end of buffer missed -
  504. This can occur in an scanner which is reentered after a long-jump
  505. has jumped out (or over) the scanner's activation frame.  Before
  506. reentering the scanner, use:
  507. .nf
  508.  
  509.     yyrestart( yyin );
  510.  
  511. .fi
  512. .LP
  513. .I too many %t classes! -
  514. You managed to put every single character into its own %t class.
  515. .I flex
  516. requires that at least one of the classes share characters.
  517. .SH DEFICIENCIES / BUGS
  518. See flex(1).
  519. .SH "SEE ALSO"
  520. .LP
  521. flex(1), lex(1), yacc(1), sed(1), awk(1).
  522. .LP
  523. M. E. Lesk and E. Schmidt,
  524. .I LEX - Lexical Analyzer Generator
  525. .SH AUTHOR
  526. Vern Paxson, with the help of many ideas and much inspiration from
  527. Van Jacobson.  Original version by Jef Poskanzer.  The fast table
  528. representation is a partial implementation of a design done by Van
  529. Jacobson.  The implementation was done by Kevin Gong and Vern Paxson.
  530. .LP
  531. Thanks to the many
  532. .I flex
  533. beta-testers, feedbackers, and contributors, especially Casey
  534. Leedom, benson@odi.com, Keith Bostic,
  535. Frederic Brehm, Nick Christopher, Jason Coughlin,
  536. Scott David Daniels, Leo Eskin,
  537. Chris Faylor, Eric Goldman, Eric
  538. Hughes, Jeffrey R. Jones, Kevin B. Kenny, Ronald Lamprecht,
  539. Greg Lee, Craig Leres, Mohamed el Lozy, Jim Meyering, Marc Nozell, Esmond Pitt,
  540. Jef Poskanzer, Jim Roskind,
  541. Dave Tallman, Frank Whaley, Ken Yap, and those whose names
  542. have slipped my marginal mail-archiving skills but whose contributions
  543. are appreciated all the same.
  544. .LP
  545. Thanks to Keith Bostic, John Gilmore, Craig Leres, Bob
  546. Mulcahy, Rich Salz, and Richard Stallman for help with various distribution
  547. headaches.
  548. .LP
  549. Thanks to Esmond Pitt and Earle Horton for 8-bit character support;
  550. to Benson Margulies and Fred
  551. Burke for C++ support; to Ove Ewerlid for the basics of support for
  552. NUL's; and to Eric Hughes for the basics of support for multiple buffers.
  553. .LP
  554. Work is being done on extending
  555. .I flex
  556. to generate scanners in which the
  557. state machine is directly represented in C code rather than tables.
  558. These scanners may well be substantially faster than those generated
  559. using -f or -F.  If you are working in this area and are interested
  560. in comparing notes and seeing whether redundant work can be avoided,
  561. contact Ove Ewerlid (ewerlid@mizar.DoCS.UU.SE).
  562. .LP
  563. This work was primarily done when I was at the Real Time Systems Group
  564. at the Lawrence Berkeley Laboratory in Berkeley, CA.  Many thanks to all there
  565. for the support I received.
  566. .LP
  567. Send comments to:
  568. .nf
  569.  
  570.      Vern Paxson
  571.      Computer Science Department
  572.      4126 Upson Hall
  573.      Cornell University
  574.      Ithaca, NY 14853-7501
  575.  
  576.      vern@cs.cornell.edu
  577.      decvax!cornell!vern
  578.  
  579. .fi
  580.