/[dynamips]/trunk/parser.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/parser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 8842 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Mini-parser.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/mman.h>
15 #include <signal.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <assert.h>
19 #include <stdarg.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <arpa/inet.h>
24
25 #include "utils.h"
26 #include "parser.h"
27
28 #define TOKEN_MAX_SIZE 512
29
30 /* Character types */
31 enum {
32 PARSER_CHAR_BLANK,
33 PARSER_CHAR_NEWLINE,
34 PARSER_CHAR_COMMENT,
35 PARSER_CHAR_QUOTE,
36 PARSER_CHAR_OTHER,
37 };
38
39 /* Get a description given an error code */
40 char *parser_strerror(parser_context_t *ctx)
41 {
42 printf("error = %d\n",ctx->error);
43
44 switch(ctx->error) {
45 case 0:
46 return "no error";
47 case PARSER_ERROR_NOMEM:
48 return "insufficient memory";
49 case PARSER_ERROR_UNEXP_QUOTE:
50 return "unexpected quote";
51 case PARSER_ERROR_UNEXP_EOL:
52 return "unexpected end of line";
53 default:
54 return "unknown error";
55 }
56 }
57
58 /* Dump a token list */
59 void parser_dump_tokens(parser_context_t *ctx)
60 {
61 parser_token_t *tok;
62
63 for(tok=ctx->tok_head;tok;tok=tok->next)
64 printf("\"%s\" ",tok->value);
65 }
66
67 /* Map a token list to an array */
68 char **parser_map_array(parser_context_t *ctx)
69 {
70 parser_token_t *tok;
71 char **map;
72 int i;
73
74 if (ctx->tok_count <= 0)
75 return NULL;
76
77 if (!(map = calloc(ctx->tok_count,sizeof(char **))))
78 return NULL;
79
80 for(i=0,tok=ctx->tok_head;(i<ctx->tok_count) && tok;i++,tok=tok->next)
81 map[i] = tok->value;
82
83 return map;
84 }
85
86 /* Add a character to temporary token (resize if necessary) */
87 static int tmp_token_add_char(parser_context_t *ctx,char c)
88 {
89 size_t new_size;
90 char *new_str;
91
92 if (!ctx->tmp_tok || (ctx->tmp_cur_len == (ctx->tmp_tot_len - 1))) {
93 new_size = ctx->tmp_tot_len + TOKEN_MAX_SIZE;
94 new_str = realloc(ctx->tmp_tok,new_size);
95
96 if (!new_str)
97 return(-1);
98
99 ctx->tmp_tok = new_str;
100 ctx->tmp_tot_len = new_size;
101 }
102
103 ctx->tmp_tok[ctx->tmp_cur_len++] = c;
104 ctx->tmp_tok[ctx->tmp_cur_len] = 0;
105 return(0);
106 }
107
108 /* Move current token to the active token list */
109 static int parser_move_tmp_token(parser_context_t *ctx)
110 {
111 parser_token_t *tok;
112
113 /* no token ... */
114 if (!ctx->tmp_tok)
115 return(0);
116
117 if (!(tok = malloc(sizeof(*tok))))
118 return(-1);
119
120 tok->value = ctx->tmp_tok;
121 tok->next = NULL;
122
123 /* add it to the token list */
124 if (ctx->tok_last != NULL)
125 ctx->tok_last->next = tok;
126 else
127 ctx->tok_head = tok;
128
129 ctx->tok_last = tok;
130 ctx->tok_count++;
131
132 /* start a new token */
133 ctx->tmp_tok = NULL;
134 ctx->tmp_tot_len = ctx->tmp_cur_len = 0;
135 return(0);
136 }
137
138 /* Initialize parser context */
139 void parser_context_init(parser_context_t *ctx)
140 {
141 ctx->tok_head = ctx->tok_last = NULL;
142 ctx->tok_count = 0;
143
144 ctx->tmp_tok = NULL;
145 ctx->tmp_tot_len = ctx->tmp_cur_len = 0;
146
147 ctx->state = PARSER_STATE_BLANK;
148 ctx->error = 0;
149
150 ctx->consumed_len = 0;
151 }
152
153 /* Free a token list */
154 void parser_free_tokens(parser_token_t *tok_list)
155 {
156 parser_token_t *t,*next;
157
158 for(t=tok_list;t;t=next) {
159 next = t->next;
160 free(t->value);
161 free(t);
162 }
163 }
164
165 /* Free memory used by a parser context */
166 void parser_context_free(parser_context_t *ctx)
167 {
168 parser_free_tokens(ctx->tok_head);
169
170 if (ctx->tmp_tok != NULL)
171 free(ctx->tmp_tok);
172
173 parser_context_init(ctx);
174 }
175
176 /* Determine the type of the input character */
177 static int parser_get_char_type(u_char c)
178 {
179 switch(c) {
180 case '\n':
181 case '\r':
182 case 0:
183 return(PARSER_CHAR_NEWLINE);
184 case '\t':
185 //case '\r':
186 case ' ':
187 return(PARSER_CHAR_BLANK);
188 case '!':
189 case '#':
190 return(PARSER_CHAR_COMMENT);
191 case '"':
192 return(PARSER_CHAR_QUOTE);
193 default:
194 return(PARSER_CHAR_OTHER);
195 }
196 }
197
198 /* Send a buffer to the tokenizer */
199 int parser_scan_buffer(parser_context_t *ctx,char *buf,size_t buf_size)
200 {
201 int i,type;
202 u_char c;
203
204 for(i=0;(i<buf_size) && (ctx->state != PARSER_STATE_DONE);i++)
205 {
206 ctx->consumed_len++;
207 c = buf[i];
208
209 /* Determine character type */
210 type = parser_get_char_type(c);
211
212 /* Basic finite state machine */
213 switch(ctx->state) {
214 case PARSER_STATE_SKIP:
215 if (type == PARSER_CHAR_NEWLINE)
216 ctx->state = PARSER_STATE_DONE;
217
218 /* Simply ignore character until we reach end of line */
219 break;
220
221 case PARSER_STATE_BLANK:
222 switch(type) {
223 case PARSER_CHAR_BLANK:
224 /* Eat space */
225 break;
226
227 case PARSER_CHAR_COMMENT:
228 ctx->state = PARSER_STATE_SKIP;
229 break;
230
231 case PARSER_CHAR_NEWLINE:
232 ctx->state = PARSER_STATE_DONE;
233 break;
234
235 case PARSER_CHAR_QUOTE:
236 ctx->state = PARSER_STATE_QUOTED_STRING;
237 break;
238
239 default:
240 /* Begin a new string */
241 if (!tmp_token_add_char(ctx,c)) {
242 ctx->state = PARSER_STATE_STRING;
243 } else {
244 ctx->state = PARSER_STATE_SKIP;
245 ctx->error = PARSER_ERROR_NOMEM;
246 }
247 }
248 break;
249
250 case PARSER_STATE_STRING:
251 switch(type) {
252 case PARSER_CHAR_BLANK:
253 if (!parser_move_tmp_token(ctx)) {
254 ctx->state = PARSER_STATE_BLANK;
255 } else {
256 ctx->state = PARSER_STATE_SKIP;
257 ctx->error = PARSER_ERROR_NOMEM;
258 }
259 break;
260
261 case PARSER_CHAR_NEWLINE:
262 if (parser_move_tmp_token(ctx) == -1)
263 ctx->error = PARSER_ERROR_NOMEM;
264
265 ctx->state = PARSER_STATE_DONE;
266 break;
267
268 case PARSER_CHAR_COMMENT:
269 if (parser_move_tmp_token(ctx) == -1)
270 ctx->error = PARSER_ERROR_NOMEM;
271
272 ctx->state = PARSER_STATE_SKIP;
273 break;
274
275 case PARSER_CHAR_QUOTE:
276 ctx->error = PARSER_ERROR_UNEXP_QUOTE;
277 ctx->state = PARSER_STATE_SKIP;
278 break;
279
280 default:
281 /* Add the character to the buffer */
282 if (tmp_token_add_char(ctx,c) == -1) {
283 ctx->state = PARSER_STATE_SKIP;
284 ctx->error = PARSER_ERROR_NOMEM;
285 }
286 }
287 break;
288
289 case PARSER_STATE_QUOTED_STRING:
290 switch(type) {
291 case PARSER_CHAR_NEWLINE:
292 /* Unterminated string! */
293 ctx->error = PARSER_ERROR_UNEXP_EOL;
294 ctx->state = PARSER_STATE_DONE;
295 break;
296
297 case PARSER_CHAR_QUOTE:
298 if (!parser_move_tmp_token(ctx)) {
299 ctx->state = PARSER_STATE_BLANK;
300 } else {
301 ctx->state = PARSER_STATE_SKIP;
302 ctx->error = PARSER_ERROR_NOMEM;
303 }
304 break;
305
306 default:
307 /* Add the character to the buffer */
308 if (tmp_token_add_char(ctx,c) == -1) {
309 ctx->state = PARSER_STATE_SKIP;
310 ctx->error = PARSER_ERROR_NOMEM;
311 }
312 }
313 break;
314 }
315 }
316
317 return(ctx->state == PARSER_STATE_DONE);
318 }
319
320 /* Parser tests */
321 static char *parser_test_str[] = {
322 "c7200 show_hardware R1",
323 "c7200 show_hardware \"R1\"",
324 " c7200 show_hardware \"R1\" ",
325 "\"c7200\" \"show_hardware\" \"R1\"",
326 "hypervisor set_working_dir \"C:\\Program Files\\Dynamips Test\"",
327 "hypervisor # This is a comment set_working_dir \"C:\\Program Files\"",
328 "\"c7200\" \"show_hardware\" \"R1",
329 NULL,
330 };
331
332 void parser_run_tests(void)
333 {
334 parser_context_t ctx;
335 int i,res;
336
337 for(i=0;parser_test_str[i];i++) {
338 parser_context_init(&ctx);
339
340 res = parser_scan_buffer(&ctx,parser_test_str[i],
341 strlen(parser_test_str[i])+1);
342
343 printf("\n%d: Test string: [%s] => res=%d, state=%d\n",
344 i,parser_test_str[i],res,ctx.state);
345
346 if ((res != 0) && (ctx.error == 0)) {
347 if (ctx.tok_head) {
348 printf("Tokens: ");
349 parser_dump_tokens(&ctx);
350 printf("\n");
351 }
352 }
353
354 parser_context_free(&ctx);
355 }
356 }

  ViewVC Help
Powered by ViewVC 1.1.26