home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Add-Ons / MPW / MPW re2c 1.1 / doc / re2c.1 < prev    next >
Encoding:
Text File  |  1995-06-01  |  15.2 KB  |  534 lines  |  [TEXT/MPS ]

  1. .ds re \fBre2c\fP
  2. .ds le \fBlex\fP
  3. .ds rx regular expression
  4. .ds lx \fIl\fP-expression
  5. .TH RE2C 1 "8 April 1994" "Version 0.5"
  6. \"$Log: re2c.1,v $
  7. \"Revision 1.2  1994/04/16  15:50:32  peter
  8. \"Fix bug in simple example.
  9. \"
  10. \"Revision 1.1  1994/04/08  15:39:09  peter
  11. \"Initial revision
  12. \"
  13. .SH NAME
  14. re2c \- convert regular expressions to C/C++
  15.  
  16. .SH SYNOPSIS
  17. \*(re [\fB-esb\fP] \fIname\fP
  18.  
  19. .SH DESCRIPTION
  20. \*(re is a preprocessor that generates C-based recognizers from regular
  21. expressions.
  22. The input to \*(re consists of C/C++ source interleaved with
  23. comments of the form \fC/*!re2c\fP ... \fC*/\fP which contain
  24. scanner specifications.
  25. In the output these comments are replaced with code that, when
  26. executed, will find the next input token and then execute
  27. some user-supplied token-specific code.
  28.  
  29. For example, given the following code
  30.  
  31. .in +3
  32. .nf
  33. #define NULL            ((char*) 0)
  34. char *scan(char *p){
  35. char *q;
  36. #define YYCTYPE         char
  37. #define YYCURSOR        p
  38. #define YYLIMIT         p
  39. #define YYMARKER        q
  40. #define YYFILL(n)
  41. /*!re2c
  42.         [0-9]+          {return YYCURSOR;}
  43.         [\\000-\\377]     {return NULL;}
  44. */
  45. }
  46. .fi
  47. .in -3
  48.  
  49. \*(re will generate
  50.  
  51. .in +3
  52. .nf
  53. /* Generated by re2c on Sat Apr 16 11:40:58 1994 */
  54. #line 1 "simple.re"
  55. #define NULL            ((char*) 0)
  56. char *scan(char *p){
  57. char *q;
  58. #define YYCTYPE         char
  59. #define YYCURSOR        p
  60. #define YYLIMIT         p
  61. #define YYMARKER        q
  62. #define YYFILL(n)
  63. {
  64.         YYCTYPE yych;
  65.         unsigned int yyaccept;
  66.         goto yy0;
  67. yy1:    ++YYCURSOR;
  68. yy0:
  69.         if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
  70.         yych = *YYCURSOR;
  71.         if(yych <= '/') goto yy4;
  72.         if(yych >= ':') goto yy4;
  73. yy2:    yych = *++YYCURSOR;
  74.         goto yy7;
  75. yy3:
  76. #line 10
  77.         {return YYCURSOR;}
  78. yy4:    yych = *++YYCURSOR;
  79. yy5:
  80. #line 11
  81.         {return NULL;}
  82. yy6:    ++YYCURSOR;
  83.         if(YYLIMIT == YYCURSOR) YYFILL(1);
  84.         yych = *YYCURSOR;
  85. yy7:    if(yych <= '/') goto yy3;
  86.         if(yych <= '9') goto yy6;
  87.         goto yy3;
  88. }
  89. #line 12
  90.  
  91. }
  92. .fi
  93. .in -3
  94.  
  95. .SH OPTIONS
  96. \*(re provides the following options:
  97. .TP
  98. \fB-e\fP
  99. Cross-compile from an ASCII platform to an EBCDIC one. 
  100. .TP
  101. \fB-s\fP
  102. Generate nested \fCif\fPs for some \fCswitch\fPes.  Many compilers need this
  103. assist to generate better code.
  104. .TP
  105. \fB-b\fP
  106. Implies \fB-s\fP.  Use bit vectors as well in the attempt to coax better
  107. code out of the compiler.  Most useful for specifications with more than a
  108. few keywords (e.g. for most programming languages).
  109.  
  110. .SH "INTERFACE CODE"
  111. Unlike other scanner generators, \*(re does not generate complete scanners:
  112. the user must supply some interface code.
  113. In particular, the user must define the following macros:
  114. .TP
  115. \fCYYCHAR\fP
  116. Type used to hold an input symbol.
  117. Usually \fCchar\fP or \fCunsigned char\fP.
  118. .TP
  119. \fCYYCURSOR\fP
  120. \*(lx of type \fC*YYCHAR\fP that points to the current input symbol.
  121. The generated code advances \fCYYCURSOR\fP as symbols are matched.
  122. On entry, \fCYYCURSOR\fP is assumed to point to the first character of the
  123. current token.  On exit, \fCYYCURSOR\fP will point to the first character of
  124. the following token.
  125. .TP
  126. \fCYLIMIT\fP
  127. Expression of type \fC*YYCHAR\fP that marks the end of the buffer
  128. (\fCYLIMIT[-1]\fP is the last character in the buffer).
  129. The generated code repeatedly compares \fCYYCURSOR\fP to \fCYLIMIT\fP
  130. to determine when the buffer needs (re)filling.
  131. .TP
  132. \fCYYMARKER\fP
  133. \*(lx of type \fC*YYCHAR\fP.
  134. The generated code saves backtracking information in \fCYYMARKER\fP.
  135. .TP
  136. \fCYYFILL(\fP\fIn\fP\fC)\fP
  137. The generated code "calls" \fCYYFILL\fP when the buffer needs
  138. (re)filling:  at least \fIn\fP additional characters should
  139. be provided.  \fCYYFILL\fP should adjust \fCYYCURSOR\fP, \fCYYLIMIT\fP and
  140. \fCYYMARKER\fP as needed.  Note that for typical programming languages
  141. \fIn\fP will be the length of the longest keyword plus one.
  142.  
  143. .SH "SCANNER SPECIFICATIONS"
  144. Each scanner specification consists of a set of \fIrules\fP and name
  145. definitions.
  146. Rules consist of a regular expression along with a block of C/C++ code that
  147. is to be executed when the associated regular expression is matched.
  148. Name definitions are of the form
  149. ``\fIname\fP \fC=\fP \fIregular expression\fP\fC;\fP''.
  150.  
  151. .SH "SUMMARY OF RE2C REGULAR EXPRESSIONS"
  152. .TP
  153. \fC"foo"\fP
  154. the literal string \fCfoo\fP.
  155. ANSI-C escape sequences can be used.
  156. .TP
  157. \fC[xyz]\fP
  158. a "character class"; in this case,
  159. the \*(rx matches either an '\fCx\fP', a '\fCy\fP', or a '\fCz\fP'.
  160. .TP
  161. \fC[abj-oZ]\fP
  162. a "character class" with a range in it;
  163. matches an '\fCa\fP', a '\fCb\fP', any letter from '\fCj\fP' through '\fCo\fP',
  164. or a '\fCZ\fP'.
  165. .TP
  166. \fIr\fP\fC\e\fP\fIs\fP
  167. match any \fIr\fP which isn't an \fIs\fP. \fIr\fP and \fIs\fP must be regular expressions
  168. which can be expressed as character classes.
  169. .TP
  170. \fIr\fP\fC*\fP
  171. zero or more \fIr\fP's, where \fIr\fP is any regular expression
  172. .TP
  173. \fC\fIr\fP\fC+\fP
  174. one or more \fIr\fP's
  175. .TP
  176. \fC\fIr\fP\fC?\fP
  177. zero or one \fIr\fP's (that is, "an optional \fIr\fP")
  178. .TP
  179. name
  180. the expansion of the "name" definition (see above)
  181. .TP
  182. \fC(\fP\fIr\fP\fC)\fP
  183. an \fIr\fP; parentheses are used to override precedence
  184. (see below)
  185. .TP
  186. \fIrs\fP
  187. an \fIr\fP followed by an \fIs\fP ("concatenation")
  188. .TP
  189. \fIr\fP\fC|\fP\fIs\fP
  190. either an \fIr\fP or an \fIs\fP
  191. .TP
  192. \fIr\fP\fC/\fP\fIs\fP
  193. an \fIr\fP but only if it is followed by an \fIs\fP. The s is not part of
  194. the matched text. This type of \*(rx is called "trailing context".
  195. .LP
  196. The regular expressions listed above are grouped according to
  197. precedence, from highest precedence at the top to lowest at the bottom.
  198. Those grouped together have equal precedence.
  199.  
  200. .SH "A LARGER EXAMPLE"
  201. .LP
  202. .in +3
  203. .nf
  204. #include <stdlib.h>
  205. #include <stdio.h>
  206. #include <fcntl.h>
  207. #include <string.h>
  208.  
  209. #define ADDEQ   257
  210. #define ANDAND  258
  211. #define ANDEQ   259
  212. #define ARRAY   260
  213. #define ASM     261
  214. #define AUTO    262
  215. #define BREAK   263
  216. #define CASE    264
  217. #define CHAR    265
  218. #define CONST   266
  219. #define CONTINUE        267
  220. #define DECR    268
  221. #define DEFAULT 269
  222. #define DEREF   270
  223. #define DIVEQ   271
  224. #define DO      272
  225. #define DOUBLE  273
  226. #define ELLIPSIS        274
  227. #define ELSE    275
  228. #define ENUM    276
  229. #define EQL     277
  230. #define EXTERN  278
  231. #define FCON    279
  232. #define FLOAT   280
  233. #define FOR     281
  234. #define FUNCTION        282
  235. #define GEQ     283
  236. #define GOTO    284
  237. #define ICON    285
  238. #define ID      286
  239. #define IF      287
  240. #define INCR    288
  241. #define INT     289
  242. #define LEQ     290
  243. #define LONG    291
  244. #define LSHIFT  292
  245. #define LSHIFTEQ        293
  246. #define MODEQ   294
  247. #define MULEQ   295
  248. #define NEQ     296
  249. #define OREQ    297
  250. #define OROR    298
  251. #define POINTER 299
  252. #define REGISTER        300
  253. #define RETURN  301
  254. #define RSHIFT  302
  255. #define RSHIFTEQ        303
  256. #define SCON    304
  257. #define SHORT   305
  258. #define SIGNED  306
  259. #define SIZEOF  307
  260. #define STATIC  308
  261. #define STRUCT  309
  262. #define SUBEQ   310
  263. #define SWITCH  311
  264. #define TYPEDEF 312
  265. #define UNION   313
  266. #define UNSIGNED        314
  267. #define VOID    315
  268. #define VOLATILE        316
  269. #define WHILE   317
  270. #define XOREQ   318
  271. #define EOI     319
  272.  
  273. typedef unsigned int uint;
  274. typedef unsigned char uchar;
  275.  
  276. #define BSIZE   8192
  277.  
  278. #define YYCTYPE         uchar
  279. #define YYCURSOR        cursor
  280. #define YYLIMIT         s->lim
  281. #define YYMARKER        s->ptr
  282. #define YYFILL(n)       {cursor = fill(s, cursor);}
  283.  
  284. #define RET(i)  {s->cur = cursor; return i;}
  285.  
  286. typedef struct Scanner {
  287.     int                 fd;
  288.     uchar               *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof;
  289.     uint                line;
  290. } Scanner;
  291.  
  292. uchar *fill(Scanner *s, uchar *cursor){
  293.     if(!s->eof){
  294.         uint cnt = s->tok - s->bot;
  295.         if(cnt){
  296.             memcpy(s->bot, s->tok, s->lim - s->tok);
  297.             s->tok = s->bot;
  298.             s->ptr -= cnt;
  299.             cursor -= cnt;
  300.             s->pos -= cnt;
  301.             s->lim -= cnt;
  302.         }
  303.         if((s->top - s->lim) < BSIZE){
  304.             uchar *buf = (uchar*)
  305.                 malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar));
  306.             memcpy(buf, s->tok, s->lim - s->tok);
  307.             s->tok = buf;
  308.             s->ptr = &buf[s->ptr - s->bot];
  309.             cursor = &buf[cursor - s->bot];
  310.             s->pos = &buf[s->pos - s->bot];
  311.             s->lim = &buf[s->lim - s->bot];
  312.             s->top = &s->lim[BSIZE];
  313.             free(s->bot);
  314.             s->bot = buf;
  315.         }
  316.         if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){
  317.             s->eof = &s->lim[cnt]; *(s->eof)++ = '\\n';
  318.         }
  319.         s->lim += cnt;
  320.     }
  321.     return cursor;
  322. }
  323.  
  324. int scan(Scanner *s){
  325.         uchar *cursor = s->cur;
  326. std:
  327.         s->tok = cursor;
  328. /*!re2c
  329. any     = [\\000-\\377];
  330. O       = [0-7];
  331. D       = [0-9];
  332. L       = [a-zA-Z_];
  333. H       = [a-fA-F0-9];
  334. E       = [Ee] [+-]? D+;
  335. FS      = [fFlL];
  336. IS      = [uUlL]*;
  337. ESC     = [\\\\] ([abfnrtv?'"\\\\] | "x" H+ | O+);
  338. */
  339.  
  340. /*!re2c
  341.         "/*"                    { goto comment; }
  342.         
  343.         "auto"                  { RET(AUTO); }
  344.         "break"                 { RET(BREAK); }
  345.         "case"                  { RET(CASE); }
  346.         "char"                  { RET(CHAR); }
  347.         "const"                 { RET(CONST); }
  348.         "continue"              { RET(CONTINUE); }
  349.         "default"               { RET(DEFAULT); }
  350.         "do"                    { RET(DO); }
  351.         "double"                { RET(DOUBLE); }
  352.         "else"                  { RET(ELSE); }
  353.         "enum"                  { RET(ENUM); }
  354.         "extern"                { RET(EXTERN); }
  355.         "float"                 { RET(FLOAT); }
  356.         "for"                   { RET(FOR); }
  357.         "goto"                  { RET(GOTO); }
  358.         "if"                    { RET(IF); }
  359.         "int"                   { RET(INT); }
  360.         "long"                  { RET(LONG); }
  361.         "register"              { RET(REGISTER); }
  362.         "return"                { RET(RETURN); }
  363.         "short"                 { RET(SHORT); }
  364.         "signed"                { RET(SIGNED); }
  365.         "sizeof"                { RET(SIZEOF); }
  366.         "static"                { RET(STATIC); }
  367.         "struct"                { RET(STRUCT); }
  368.         "switch"                { RET(SWITCH); }
  369.         "typedef"               { RET(TYPEDEF); }
  370.         "union"                 { RET(UNION); }
  371.         "unsigned"              { RET(UNSIGNED); }
  372.         "void"                  { RET(VOID); }
  373.         "volatile"              { RET(VOLATILE); }
  374.         "while"                 { RET(WHILE); }
  375.         
  376.         L (L|D)*                { RET(ID); }
  377.         
  378.         ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) |
  379.         (['] (ESC|any\\[\\n\\\\'])* ['])
  380.                                 { RET(ICON); }
  381.         
  382.         (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?)
  383.                                 { RET(FCON); }
  384.         
  385.         (["] (ESC|any\\[\\n\\\\"])* ["])
  386.                                 { RET(SCON); }
  387.         
  388.         "..."                   { RET(ELLIPSIS); }
  389.         ">>="                   { RET(RSHIFTEQ); }
  390.         "<<="                   { RET(LSHIFTEQ); }
  391.         "+="                    { RET(ADDEQ); }
  392.         "-="                    { RET(SUBEQ); }
  393.         "*="                    { RET(MULEQ); }
  394.         "/="                    { RET(DIVEQ); }
  395.         "%="                    { RET(MODEQ); }
  396.         "&="                    { RET(ANDEQ); }
  397.         "^="                    { RET(XOREQ); }
  398.         "|="                    { RET(OREQ); }
  399.         ">>"                    { RET(RSHIFT); }
  400.         "<<"                    { RET(LSHIFT); }
  401.         "++"                    { RET(INCR); }
  402.         "--"                    { RET(DECR); }
  403.         "->"                    { RET(DEREF); }
  404.         "&&"                    { RET(ANDAND); }
  405.         "||"                    { RET(OROR); }
  406.         "<="                    { RET(LEQ); }
  407.         ">="                    { RET(GEQ); }
  408.         "=="                    { RET(EQL); }
  409.         "!="                    { RET(NEQ); }
  410.         ";"                     { RET(';'); }
  411.         "{"                     { RET('{'); }
  412.         "}"                     { RET('}'); }
  413.         ","                     { RET(','); }
  414.         ":"                     { RET(':'); }
  415.         "="                     { RET('='); }
  416.         "("                     { RET('('); }
  417.         ")"                     { RET(')'); }
  418.         "["                     { RET('['); }
  419.         "]"                     { RET(']'); }
  420.         "."                     { RET('.'); }
  421.         "&"                     { RET('&'); }
  422.         "!"                     { RET('!'); }
  423.         "~"                     { RET('~'); }
  424.         "-"                     { RET('-'); }
  425.         "+"                     { RET('+'); }
  426.         "*"                     { RET('*'); }
  427.         "/"                     { RET('/'); }
  428.         "%"                     { RET('%'); }
  429.         "<"                     { RET('<'); }
  430.         ">"                     { RET('>'); }
  431.         "^"                     { RET('^'); }
  432.         "|"                     { RET('|'); }
  433.         "?"                     { RET('?'); }
  434.  
  435.  
  436.         [ \\t\\v\\f]+           { goto std; }
  437.  
  438.         "\\n"
  439.             {
  440.                 if(cursor == s->eof) RET(EOI);
  441.                 s->pos = cursor; s->line++;
  442.                 goto std;
  443.             }
  444.  
  445.         any
  446.             {
  447.                 printf("unexpected character: %c\\n", *s->tok);
  448.                 goto std;
  449.             }
  450. */
  451.  
  452. comment:
  453. /*!re2c
  454.         "*/"                    { goto std; }
  455.         "\\n"
  456.             {
  457.                 if(cursor == s->eof) RET(EOI);
  458.                 s->tok = s->pos = cursor; s->line++;
  459.                 goto comment;
  460.             }
  461.         any                     { goto comment; }
  462. */
  463. }
  464.  
  465. main(){
  466.     Scanner in;
  467.     int t;
  468.     memset((char*) &in, 0, sizeof(in));
  469.     in.fd = 0;
  470.     while((t = scan(&in)) != EOI){
  471. /*
  472.         printf("%d\\t%.*s\\n", t, in.cur - in.tok, in.tok);
  473.         printf("%d\\n", t);
  474. */
  475.     }
  476.     close(in.fd);
  477. }
  478. .fi
  479. .in -3
  480.  
  481. .SH "SEE ALSO"
  482. .LP
  483. flex(1), lex(1).
  484.  
  485. .SH FEATURES
  486. .LP
  487. \*(re does not provide a default action:
  488. the generated code assumes that the input
  489. will consist of a sequence of tokens.
  490. Typically this can be dealt with by adding a rule such as the one for
  491. unexpected characters in the example above.
  492. .LP
  493. The user must arrange for a sentinel token to appear at the end of input
  494. (and provide a rule for matching it):
  495. \*(re does not provide an \fC<<EOF>>\fP expression.
  496. If the source is from a null-byte terminated string, a
  497. rule matching a null character will suffice.  If the source is from a
  498. file then the approach taken in the example can be used: pad the input with
  499. a newline (or some other character that can't appear within another token);
  500. upon recognizing such a character check to see if it is the sentinel
  501. and act accordingly.
  502. .LP
  503. \*(re does not provide start conditions:  use a separate scanner
  504. specification for each start condition (as illustrated in the above example).
  505. .LP
  506. No [^x].  Use difference instead.
  507. .SH BUGS
  508. .LP
  509. Only fixed length trailing context can be handled.
  510. .LP
  511. The maximum value appearing as a parameter \fIn\fP to \fCYYFILL\fP is not
  512. provided to the generated code (this value is needed for constructing
  513. the interface code).
  514. Note that this value is usually relatively small: for
  515. typical programming languages \fIn\fP will be the length of the longest
  516. keyword plus one.
  517. .LP
  518. Difference only works for character sets.
  519. .LP
  520. The \*(re internal algorithms need documentation.
  521.  
  522. .SH AUTHOR
  523. .LP
  524. Please send bug reports, fixes and feedback to:
  525. .LP
  526. .nf
  527. Peter Bumbulis
  528. Computer Systems Group
  529. University of Waterloo
  530. Waterloo, Ontario
  531. N2L 3G1
  532. Internet:  peter@csg.uwaterloo.ca
  533. .fi
  534.