-
Notifications
You must be signed in to change notification settings - Fork 12
/
parser-tools.rl
239 lines (189 loc) · 6.22 KB
/
parser-tools.rl
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
File: parser-tools.rl
Ragel state-machine actions and definitions used to build parsers.
(c)2015-2017, Levien van Zon (levien at zonnetjes.net, https://github.com/lvzon)
*/
%%{
machine parser;
access fsm->;
# A buffer to collect command arguments
# Append to the string buffer.
action str_append {
if ( fsm->buflen < PARSER_BUFLEN )
fsm->buffer[fsm->buflen++] = fc;
}
# Terminate a buffer.
action str_term {
if ( fsm->buflen < PARSER_BUFLEN )
fsm->buffer[fsm->buflen++] = 0;
}
# Clear out the buffer
action clearbuf { fsm->buflen = 0; }
# Add a new integer argument to the stack
action addarg {
fsm->arg[fsm->argc] *= fsm->multiplier;
if ( fsm->argc < PARSER_MAXARGS )
fsm->argc++;
fsm->multiplier = 1;
}
# Add a new non-integer arguments to the stack, as integer value and divider
action addfparg {
// Add integer value
fsm->arg[fsm->argc] *= fsm->multiplier;
if ( fsm->argc < PARSER_MAXARGS )
fsm->argc++;
fsm->multiplier = 1;
// Add divider, calculated as 10^decimalpos, the decimal position from the end
//printf("Decimal position: %d\n", fsm->decimalpos);
if (fsm->decimalpos >= 0 && fsm->decimalpos <= MAX_DIVIDER_EXP)
fsm->arg[fsm->argc] = pow10[fsm->decimalpos];
else if (fsm->decimalpos == -1)
fsm->arg[fsm->argc] = 1;
else
fsm->arg[fsm->argc] = 0;
if ( fsm->argc < PARSER_MAXARGS )
fsm->argc++;
fsm->decimalpos = -1;
}
# Push a string onto the string argument stack
action addstr {
if ( fsm->strargc < PARSER_MAXARGS )
fsm->strarg[fsm->strargc++] = fsm->buffer + fsm->buflen;
}
# Add a single character argument to the stack
action addchar {
fsm->arg[fsm->argc] = fc;
if ( fsm->argc < PARSER_MAXARGS )
fsm->argc++;
}
# Set current argument to zero
action cleararg {
fsm->arg[fsm->argc] = 0;
fsm->bitcount = 0;
fsm->decimalpos = -1;
}
# Set all arguments to zero
action clearargs {
int arg;
for (arg = 0 ; arg < fsm->argc ; arg++) {
// printf("clearing argument %d of %d\n", arg, fsm->argc);
fsm->arg[arg] = 0;
}
fsm->multiplier = 1;
fsm->argc = 0;
fsm->bitcount = 0;
fsm->decimalpos = -1;
for (arg = 0 ; arg < fsm->strargc ; arg++) {
fsm->strarg[arg] = NULL;
}
fsm->strargc = 0;
fsm->buflen = 0;
}
# Set next lowest bit in the current argument
action addbit1_low {
fsm->arg[fsm->argc] = (fsm->arg[fsm->argc] << 1) | 1;
}
# Clear next lowest bit in the current argument
action addbit0_low {
fsm->arg[fsm->argc] <<= 1;
}
# Set next highest bit in the current argument
action addbit1_high {
fsm->arg[fsm->argc] = fsm->arg[fsm->argc] | (1 << fsm->bitcount++);
}
# Clear next highest bit in the current argument
action addbit0_high {
fsm->arg[fsm->argc] = fsm->arg[fsm->argc] & ~(1 << fsm->bitcount++);
}
# Add a decimal digit to the current argument
action add_digit {
fsm->arg[fsm->argc] = fsm->arg[fsm->argc] * 10 + (fc - '0');
}
# Add a decimal digit to the current argument, and track the decimal point position
action add_fpdigit {
if (fc == '.') {
fsm->decimalpos = 0;
} else {
fsm->arg[fsm->argc] = fsm->arg[fsm->argc] * 10 + (fc - '0');
if (fsm->decimalpos >= 0) {
// Everytime we see a digit after the decimal point, increase counter
fsm->decimalpos += 1;
}
}
}
# Add a hexadecimal digit to the current argument
action add_hexdigit {
int value;
if (isdigit(fc)) {
value = fc - '0';
} else if (isupper(fc)) {
value = fc - 'A' + 10;
} else {
value = fc - 'a' + 10;
}
fsm->arg[fsm->argc] = fsm->arg[fsm->argc] * 16 + value;
}
# Negate the current argument
action negate {
fsm->multiplier = -1;
}
# Get an unsigned int from the stack and append it as byte-value to the byte-buffer.
action byte_append {
fsm->argc--;
unsigned char byte = fsm->arg[fsm->argc] & 0xff;
unsigned char *dest;
if ( fsm->buflen < PARSER_BUFLEN ) {
dest = (unsigned char *)(fsm->buffer) + fsm->buflen++;
*dest = byte;
}
fsm->arg[fsm->argc] = 0;
fsm->bitcount = 0;
}
# Write a high nibble-value to the last byte of the byte-buffer.
action hexnibblehigh_append {
unsigned int value;
if (isdigit(fc)) {
value = fc - '0';
} else if (isupper(fc)) {
value = fc - 'A' + 10;
} else {
value = fc - 'a' + 10;
}
unsigned char byte = value << 4;
unsigned char *dest;
if ( fsm->buflen < PARSER_BUFLEN ) {
dest = (unsigned char *)(fsm->buffer) + fsm->buflen;
*dest = byte;
}
}
# Append a low nibble-value to the byte-buffer.
action hexnibblelow_append {
unsigned int value;
if (isdigit(fc)) {
value = fc - '0';
} else if (isupper(fc)) {
value = fc - 'A' + 10;
} else {
value = fc - 'a' + 10;
}
unsigned char nibble = value & 0x0f;
unsigned char *dest;
if ( fsm->buflen < PARSER_BUFLEN ) {
dest = (unsigned char *)(fsm->buffer) + fsm->buflen++;
*dest = (*dest & 0xf0) | nibble;
}
}
# Helpers to collect arguments
string = ^[\0\n;]+ >addstr $str_append %str_term;
integer = ( ('-' @negate) | '+' )? ( digit @add_digit )+ >cleararg %addarg; # Parse and store signed integer argument
uinteger = ( digit @add_digit )+ >cleararg %addarg; # Parse and store unsigned integer arument
fpval = ( ('-' @negate) | '+' )? ( [1234567890.] @add_fpdigit )+ >cleararg %addfparg; # Parse and store non-integer numeric argument
hexint = '0x'? ( xdigit @add_hexdigit )+ >cleararg %addarg; # Parse and store unsigned hexadecimal integer argument
bitmask = ( '0b'? '0'@addbit0_low | '1'@addbit1_low )+ >cleararg %addarg; # Parse and store binary argument (MSB first)
reversebitmask = ( '0'@addbit0_high | '1'@addbit1_high )+ >cleararg %addarg; # Parse and store reversed bitstring argument (LSB first)
bitval = ('0x' hexint | '0b' bitmask | reversebitmask); # A bitmask in hex or binary or as reverse-bitstring
uintval = ('0x' hexint | uinteger); # A numeric value as hex or unsigned integer
bytes = (uintval @byte_append space+?)+; # A sequence of numeric byte values (0x00 - 0xff or 0 - 255) separated by spaces
hexoctet = (xdigit @hexnibblehigh_append) (xdigit @hexnibblelow_append); # A byte represented as two hex digits
hexstring = hexoctet+ >addstr %str_term; # Parse and store unsigned hexadecimal integer argument
}%%