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