Added to paragraph on build_parsers.
[external/ragel.git] / examples / format.rl
1 /*
2  * Partial printf implementation.
3  */
4
5 #define BUFLEN 1024
6 #include <stdio.h>
7
8 typedef void (*WriteFunc)( char *data, int len );
9
10 struct format
11 {
12         char buf[BUFLEN+1];
13         int buflen;
14         WriteFunc write;
15
16         int flags;
17         int width;
18         int prec;
19         int cs;
20 };
21
22 void do_conv( struct format *fsm, char c )
23 {
24         printf( "flags: %x\n", fsm->flags );
25         printf( "width: %i\n", fsm->width );
26         printf( "prec: %i\n", fsm->prec );
27         printf( "conv: %c\n", c );
28         printf( "\n" );
29 }
30
31 #define FL_HASH          0x01
32 #define FL_ZERO          0x02
33 #define FL_DASH          0x04
34 #define FL_SPACE         0x08
35 #define FL_PLUS          0x10
36
37 #define FL_HAS_WIDTH   0x0100
38 #define FL_WIDTH_ARG   0x0200
39 #define FL_HAS_PREC    0x0400
40 #define FL_PREC_ARG    0x0800
41
42 #define FL_LEN_H     0x010000
43 #define FL_LEN_HH    0x020000
44 #define FL_LEN_L     0x040000
45 #define FL_LEN_LL    0x080000
46
47 %%{
48         machine format;
49         access fsm->;
50
51         action clear {
52                 fsm->flags = 0;
53                 fsm->width = 0;
54                 fsm->prec = 0;
55         }
56
57         # A non-zero number.
58         nznum = [1-9] [0-9]*;
59
60         # Width
61         action width_num { fsm->width = 10 * fsm->width + (fc-'0'); }
62         action width_arg { fsm->flags |= FL_WIDTH_ARG; }
63         action width { fsm->flags |= FL_HAS_WIDTH; }
64         width = ( ( nznum $width_num | '*' @width_arg ) %width )?;
65
66         # Precision
67         action prec_num { fsm->prec = 10 * fsm->prec + (fc-'0'); }
68         action prec_arg { fsm->flags |= FL_PREC_ARG; }
69         action prec { fsm->flags |= FL_HAS_PREC; }
70         precision = ( '.' ( digit* $prec_num %prec | '*' @prec_arg ) )?;
71
72         # Flags
73         action flags_hash { fsm->flags |= FL_HASH; }
74         action flags_zero { fsm->flags |= FL_ZERO; }
75         action flags_dash { fsm->flags |= FL_DASH; }
76         action flags_space { fsm->flags |= FL_SPACE; }
77         action flags_plus { fsm->flags |= FL_PLUS; }
78
79         flags = ( 
80                 '#' @flags_hash |
81                 '0' @flags_zero |
82                 '-' @flags_dash |
83                 ' ' @flags_space |
84                 '+' @flags_plus )*;
85
86         action length_h  { fsm->flags |= FL_LEN_H; }
87         action length_l  { fsm->flags |= FL_LEN_L; }
88         action length_hh { fsm->flags |= FL_LEN_HH; }
89         action length_ll { fsm->flags |= FL_LEN_LL; }
90
91         # Must use leaving transitions on 'h' and 'l' because they are
92         # prefixes for 'hh' and 'll'.
93         length = (
94                 'h' %length_h | 
95                 'l' %length_l |
96                 'hh' @length_hh |
97                 'll' @length_ll )?;
98         
99         action conversion { 
100                 do_conv( fsm, fc );
101         }
102
103         conversion = [diouxXcsp] @conversion;
104
105         fmt_spec = 
106                         '%' @clear 
107                         flags
108                         width
109                         precision
110                         length
111                         conversion;
112         
113         action emit {
114                 if ( fsm->buflen == BUFLEN ) {
115                         fsm->write( fsm->buf, fsm->buflen );
116                         fsm->buflen = 0;
117                 }
118                 fsm->buf[fsm->buflen++] = fc;
119         }
120
121         action finish_ok {
122                 if ( fsm->buflen > 0 )
123                         fsm->write( fsm->buf, fsm->buflen );
124         }
125         action finish_err {
126                 printf("EOF IN FORMAT\n");
127         }
128         action err_char {
129                 printf("ERROR ON CHAR: 0x%x\n", fc );
130         }
131
132         main := ( 
133                         [^%] @emit | 
134                         '%%' @emit | 
135                         fmt_spec 
136                 )* @/finish_err %/finish_ok $!err_char;
137 }%%
138
139 %% write data;
140
141 void format_init( struct format *fsm )
142 {
143         fsm->buflen = 0;
144         %% write init;
145 }
146
147 void format_execute( struct format *fsm, const char *data, int len, int isEof )
148 {
149         const char *p = data;
150         const char *pe = data + len;
151         const char *eof = isEof ? pe : 0;
152
153         %% write exec;
154 }
155
156 int format_finish( struct format *fsm )
157 {
158         if ( fsm->cs == format_error )
159                 return -1;
160         if ( fsm->cs >= format_first_final )
161                 return 1;
162         return 0;
163 }
164
165
166 #define INPUT_BUFSIZE 2048
167
168 struct format fsm;
169 char buf[INPUT_BUFSIZE];
170
171 void write(char *data, int len )
172 {
173         fwrite( data, 1, len, stdout );
174 }
175
176 int main()
177 {
178         fsm.write = write;
179         format_init( &fsm );
180         while ( 1 ) {
181                 int len = fread( buf, 1, INPUT_BUFSIZE, stdin );
182                 int eof = len != INPUT_BUFSIZE;
183                 format_execute( &fsm, buf, len, eof );
184                 if ( eof )
185                         break;
186         }
187         if ( format_finish( &fsm ) <= 0 )
188                 printf("FAIL\n");
189         return 0;
190 }
191