Sat, 04 Nov 2000 21:14:52 +0100
trunk: changeset 30
Added LIBTU_NO_ERRMSG so snprintf is not needed with programs that
don't use the errmsg functions (pwm).
0 | 1 | /* |
2 | * libtu/tokenizer.c | |
3 | * | |
9 | 4 | * Copyright (c) Tuomo Valkonen 1999-2000. |
0 | 5 | * See the included file LICENSE for details. |
6 | */ | |
7 | ||
8 | #include <errno.h> | |
9 | #include <stdio.h> | |
10 | #include <ctype.h> | |
11 | #include <limits.h> | |
12 | #include <assert.h> | |
13 | #include <math.h> | |
14 | #include <string.h> | |
15 | ||
5 | 16 | #include <libtu/tokenizer.h> |
17 | #include <libtu/misc.h> | |
18 | #include <libtu/output.h> | |
0 | 19 | |
20 | ||
21 | static const char *errors[]={ | |
22 | DUMMY_TR("(no error)"), | |
23 | DUMMY_TR("Unexpected end of file"), /* E_TOKZ_UNEXPECTED_EOF */ | |
24 | DUMMY_TR("Unexpected end of line"), /* E_TOKZ_UNEXPECTED_EOL */ | |
25 | DUMMY_TR("End of line expected"), /* E_TOKZ_EOL_EXPECTED */ | |
26 | DUMMY_TR("Invalid character"), /* E_TOKZ_INVALID_CHAR*/ | |
27 | DUMMY_TR("Numeric constant too big"), /* E_TOKZ_TOOBIG */ | |
28 | DUMMY_TR("Invalid numberic format"), /* E_TOKZ_NUMFMT */ | |
29 | DUMMY_TR("Junk after numeric constant"), /* E_TOKZ_NUM_JUNK */ | |
30 | DUMMY_TR("Not an integer"), /* E_TOKZ_NOTINT */ | |
31 | DUMMY_TR("Numeric constant out of range"), /* E_TOKZ_RANGE */ | |
32 | DUMMY_TR("Multi-character character constant"), /* E_TOKZ_MULTICHAR */ | |
33 | DUMMY_TR("Token/statement limit reached"), /* E_TOKZ_TOKEN_LIMIT */ | |
34 | DUMMY_TR("Unknown option"), /* E_TOKZ_UNKONWN_OPTION */ | |
35 | DUMMY_TR("Syntax error"), /* E_TOKZ_SYNTAX */ | |
36 | DUMMY_TR("Invalid argument"), /* E_TOKZ_INVALID_ARGUMENT */ | |
37 | DUMMY_TR("End of statement expected"), /* E_TOKZ_EOS_EXPECTED */ | |
38 | DUMMY_TR("Too few arguments"), /* E_TOKZ_TOO_FEW_ARGS */ | |
39 | DUMMY_TR("Too many arguments"), /* E_TOKZ_TOO_MANY_ARGS */ | |
40 | DUMMY_TR("Maximum section nestin level exceeded"), /* E_TOK_Z_MAX_NEST */ | |
41 | DUMMY_TR("Identifier expected"), /* E_TOKZ_IDENTIFIER_EXPECTED */ | |
2 | 42 | DUMMY_TR("Starting brace ('{') expected"), /* E_TOKZ_LBRACE_EXPECTED */ |
0 | 43 | }; |
44 | ||
45 | ||
46 | /* */ | |
47 | ||
48 | #define STRBLEN 32 | |
49 | ||
2 | 50 | #define STRING_DECL(X) int err=0; char* X=NULL; char X##_tmp[STRBLEN]; int X##_tmpl=0 |
51 | #define STRING_DECL_P(X, P) int err=0; char* X=NULL; char X##_tmp[STRBLEN]=P; int X##_tmpl=sizeof(P)-1 | |
52 | #define STRING_APPEND(X, C) {if(!_string_append(&X, X##_tmp, &X##_tmpl, c)) err=-ENOMEM;} | |
0 | 53 | #define STRING_FREE(X) if(X!=NULL) free(X) |
2 | 54 | #define STRING_FINISH(X) {if(err!=0) return err; if(!_string_finish(&X, X##_tmp, X##_tmpl)) err=-ENOMEM;} |
0 | 55 | |
56 | ||
57 | static bool _string_append(char **p, char *tmp, int *tmplen, char c) | |
58 | { | |
59 | char *tmp2; | |
60 | ||
61 | if(*tmplen==STRBLEN-1){ | |
62 | tmp[STRBLEN-1]='\0'; | |
63 | if(*p!=NULL){ | |
64 | tmp2=scat(*p, tmp); | |
65 | free(*p); | |
66 | *p=tmp2; | |
67 | }else{ | |
68 | *p=scopy(tmp); | |
69 | } | |
70 | *tmplen=1; | |
71 | tmp[0]=c; | |
72 | return *p!=NULL; | |
73 | }else{ | |
74 | tmp[(*tmplen)++]=c; | |
75 | return TRUE; | |
76 | } | |
77 | } | |
78 | ||
79 | ||
80 | static bool _string_finish(char **p, char *tmp, int tmplen) | |
81 | { | |
82 | char *tmp2; | |
83 | ||
84 | if(tmplen==0){ | |
85 | if(*p==NULL) | |
86 | *p=scopy(""); | |
87 | }else{ | |
88 | tmp[tmplen]='\0'; | |
89 | if(*p!=NULL){ | |
90 | tmp2=scat(*p, tmp); | |
91 | free(*p); | |
92 | *p=tmp2; | |
93 | }else{ | |
94 | *p=scopy(tmp); | |
95 | } | |
96 | } | |
97 | return *p!=NULL; | |
98 | } | |
99 | ||
100 | ||
101 | /* */ | |
102 | ||
103 | ||
104 | #define INC_LINE() tokz->line++ | |
105 | #define GETCH() _getch(tokz) | |
106 | #define UNGETCH(C) _ungetch(tokz, C) | |
107 | ||
108 | static int _getch(Tokenizer *tokz) | |
109 | { | |
110 | int c; | |
111 | ||
112 | if(tokz->ungetc!=-1){ | |
113 | c=tokz->ungetc; | |
114 | tokz->ungetc=-1; | |
115 | }else{ | |
116 | c=getc(tokz->file); | |
117 | } | |
20 | 118 | |
0 | 119 | return c; |
120 | } | |
121 | ||
122 | ||
123 | static void _ungetch(Tokenizer *tokz, int c) | |
124 | { | |
125 | tokz->ungetc=c; | |
126 | } | |
127 | ||
128 | ||
129 | /* */ | |
130 | ||
131 | ||
132 | static int scan_line_comment(Token *tok, Tokenizer *tokz) | |
133 | { | |
134 | STRING_DECL_P(s, "#"); | |
135 | int c; | |
136 | ||
137 | c=GETCH(); | |
138 | ||
139 | while(c!='\n' && c!=EOF){ | |
140 | STRING_APPEND(s, c); | |
141 | c=GETCH(); | |
142 | } | |
143 | ||
144 | UNGETCH(c); | |
145 | ||
146 | STRING_FINISH(s); | |
147 | ||
148 | TOK_SET_COMMENT(tok, s); | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
153 | ||
154 | static int skip_line_comment(Tokenizer *tokz) | |
155 | { | |
156 | int c; | |
157 | ||
158 | do{ | |
159 | c=GETCH(); | |
160 | }while(c!='\n' && c!=EOF); | |
161 | ||
162 | UNGETCH(c); | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
167 | ||
168 | /* */ | |
169 | ||
170 | ||
171 | static int scan_c_comment(Token *tok, Tokenizer *tokz) | |
172 | { | |
173 | STRING_DECL_P(s, "/*"); | |
174 | int c; | |
175 | int st=0; | |
176 | ||
177 | while(1){ | |
178 | c=GETCH(); | |
179 | ||
180 | if(c==EOF){ | |
181 | STRING_FREE(s); | |
182 | return E_TOKZ_UNEXPECTED_EOF; | |
183 | } | |
184 | ||
185 | STRING_APPEND(s, c); | |
186 | ||
187 | if(c=='\n'){ | |
188 | INC_LINE(); | |
189 | }else if(st==0 && c=='*'){ | |
190 | st=1; | |
191 | }else if(st==1){ | |
192 | if(c=='/') | |
193 | break; | |
194 | st=0; | |
195 | } | |
196 | } | |
197 | ||
198 | STRING_FINISH(s); | |
199 | ||
200 | TOK_SET_COMMENT(tok, s); | |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
205 | ||
206 | static int skip_c_comment(Tokenizer *tokz) | |
207 | { | |
208 | int c; | |
209 | int st=0; | |
210 | ||
211 | while(1){ | |
212 | c=GETCH(); | |
213 | ||
214 | if(c==EOF) | |
215 | return E_TOKZ_UNEXPECTED_EOF; | |
216 | ||
217 | if(c=='\n') | |
218 | INC_LINE(); | |
219 | else if(st==0 && c=='*') | |
220 | st=1; | |
221 | else if(st==1){ | |
222 | if(c=='/') | |
223 | break; | |
224 | st=0; | |
225 | } | |
226 | } | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | ||
232 | /* */ | |
233 | ||
234 | ||
235 | static int scan_char_escape(Tokenizer *tokz) | |
236 | { | |
237 | static char* special_chars="nrtbae"; | |
238 | static char* specials="\n\r\t\b\a\033"; | |
239 | int base, max; | |
240 | int i ,c; | |
241 | ||
242 | c=GETCH(); | |
243 | ||
244 | for(i=0;special_chars[i];i++){ | |
245 | if(special_chars[i]==c) | |
246 | return specials[c]; | |
247 | } | |
248 | ||
249 | if(c=='x' || c=='X'){ | |
250 | base=16;max=2;i=0; | |
251 | }else if(c=='d' || c=='D'){ | |
252 | base=10;max=3;i=0; | |
253 | }else if(c=='8' || c=='9'){ | |
254 | base=10;max=2;i=c-'0'; | |
255 | }else if('0'<=c && c<='7'){ | |
256 | base=8;max=2;i=c-'0'; | |
257 | }else if(c=='\n'){ | |
258 | UNGETCH(c); | |
259 | return -2; | |
260 | }else{ | |
261 | return c; | |
262 | } | |
263 | ||
264 | ||
265 | while(--max>=0){ | |
266 | c=GETCH(); | |
267 | ||
268 | if(c==EOF) | |
269 | return EOF; | |
270 | ||
271 | if(c=='\n'){ | |
272 | UNGETCH(c); | |
273 | return -2; | |
274 | } | |
275 | ||
276 | if(base==16){ | |
277 | if(!isxdigit(c)) | |
278 | break; | |
279 | ||
280 | i<<=4; | |
281 | ||
282 | if(isdigit(c)) | |
283 | i+=c-'0'; | |
284 | else if(i>='a') | |
285 | i+=0xa+c-'a'; | |
286 | else | |
287 | i+=0xa+c-'a'; | |
288 | ||
289 | }else if(base==10){ | |
290 | if(!isdigit(c)) | |
291 | break; | |
292 | i*=10; | |
293 | i+=c-'0'; | |
294 | }else{ | |
295 | if(c<'0' || c>'7') | |
296 | break; | |
297 | i<<=3; | |
298 | i+=c-'0'; | |
299 | } | |
300 | } | |
301 | ||
302 | if(max>=0) | |
303 | UNGETCH(c); | |
304 | ||
305 | return i; | |
306 | } | |
307 | ||
308 | ||
309 | /* */ | |
310 | ||
311 | ||
312 | static int scan_string(Token *tok, Tokenizer *tokz, bool escapes) | |
313 | { | |
314 | STRING_DECL(s); | |
315 | int c; | |
316 | ||
317 | while(1){ | |
318 | c=GETCH(); | |
319 | ||
320 | if(c=='"') | |
321 | break; | |
322 | ||
323 | if(c=='\n'){ | |
324 | UNGETCH(c); | |
325 | STRING_FREE(s); | |
326 | return E_TOKZ_UNEXPECTED_EOL; | |
327 | } | |
328 | ||
329 | if(c=='\\' && escapes){ | |
330 | c=scan_char_escape(tokz); | |
331 | if(c==-2){ | |
332 | STRING_FREE(s); | |
333 | return E_TOKZ_UNEXPECTED_EOL; | |
334 | } | |
335 | } | |
336 | ||
337 | if(c==EOF){ | |
338 | STRING_FREE(s); | |
339 | return E_TOKZ_UNEXPECTED_EOF; | |
340 | } | |
341 | ||
342 | STRING_APPEND(s, c); | |
343 | } | |
344 | ||
345 | STRING_FINISH(s); | |
346 | ||
347 | TOK_SET_STRING(tok, s); | |
348 | ||
349 | return 0; | |
350 | } | |
351 | ||
352 | ||
353 | /* */ | |
354 | ||
355 | ||
356 | static int scan_char(Token *tok, Tokenizer *tokz) | |
357 | { | |
358 | int c, c2; | |
359 | ||
360 | c=GETCH(); | |
361 | ||
362 | if(c==EOF) | |
363 | return E_TOKZ_UNEXPECTED_EOF; | |
364 | ||
365 | if(c=='\n') | |
366 | return E_TOKZ_UNEXPECTED_EOL; | |
367 | ||
368 | if(c=='\\'){ | |
369 | c=scan_char_escape(tokz); | |
370 | ||
371 | if(c==EOF) | |
372 | return E_TOKZ_UNEXPECTED_EOF; | |
373 | ||
374 | if(c==-2) | |
375 | return E_TOKZ_UNEXPECTED_EOL; | |
376 | } | |
377 | ||
378 | c2=GETCH(); | |
379 | ||
380 | if(c2!='\'') | |
381 | return E_TOKZ_MULTICHAR; | |
382 | ||
383 | TOK_SET_CHAR(tok, c); | |
384 | ||
385 | return 0; | |
386 | } | |
387 | ||
388 | ||
389 | /* */ | |
390 | ||
391 | ||
392 | #define START_IDENT(X) (isalpha(X) || X=='_' || X=='$') | |
393 | ||
394 | ||
395 | static int scan_identifier(Token *tok, Tokenizer *tokz, int c) | |
396 | { | |
397 | STRING_DECL(s); | |
398 | ||
399 | do{ | |
400 | STRING_APPEND(s, c); | |
401 | c=GETCH(); | |
402 | }while(isalnum(c) || c=='_' || c=='$'); | |
403 | ||
404 | UNGETCH(c); | |
405 | ||
406 | STRING_FINISH(s); | |
407 | ||
408 | TOK_SET_IDENT(tok, s); | |
409 | ||
410 | return 0; | |
411 | } | |
412 | ||
3 | 413 | #define NP_SIMPLE_IMPL |
0 | 414 | #include "numparser2.h" |
415 | #include "np-conv.h" | |
416 | ||
417 | ||
418 | static int scan_number(Token *tok, Tokenizer *tokz, int c) | |
419 | { | |
420 | NPNum num=NUM_INIT; | |
421 | int e; | |
422 | ||
423 | if((e=parse_number(&num, tokz, c))) | |
424 | return e; | |
425 | ||
426 | if(num.type==NPNUM_INT){ | |
427 | long l; | |
428 | if((e=num_to_long(&l, &num, TRUE))) | |
429 | return e; | |
430 | ||
431 | TOK_SET_LONG(tok, l); | |
432 | }else if(num.type==NPNUM_FLOAT){ | |
433 | double d; | |
434 | if((e=num_to_double(&d, &num))) | |
435 | return e; | |
436 | ||
437 | TOK_SET_DOUBLE(tok, d); | |
438 | }else{ | |
439 | return E_TOKZ_NUMFMT; | |
440 | } | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | ||
446 | /* */ | |
447 | ||
448 | ||
449 | static uchar op_map[]={ | |
450 | 0x00, /* ________ 0-7 */ | |
451 | 0x00, /* ________ 8-15 */ | |
452 | 0x00, /* ________ 16-23 */ | |
453 | 0x00, /* ________ 24-31 */ | |
454 | 0x62, /* _!___%&_ 32-39 */ | |
455 | 0xff, /* ()*+,-./ 40-47 */ | |
456 | 0x00, /* ________ 48-55 */ | |
457 | 0xfc, /* __:;<=>? 56-63 */ | |
458 | 0x01, /* @_______ 64-71 */ | |
459 | 0x00, /* ________ 72-79 */ | |
460 | 0x00, /* ________ 80-87 */ | |
461 | 0x78, /* ___[_]^_ 88-95 */ | |
462 | 0x00, /* ________ 96-103 */ | |
463 | 0x00, /* ________ 104-111 */ | |
464 | 0x00, /* ________ 112-119 */ | |
465 | 0x38 /* ___{|}__ 120-127 */ | |
466 | }; | |
467 | ||
468 | ||
469 | static bool map_isset(uchar *map, uint ch) | |
470 | { | |
471 | if(ch>127) | |
472 | return FALSE; | |
473 | ||
474 | return map[ch>>3]&(1<<(ch&7)); | |
475 | } | |
476 | ||
477 | ||
478 | static bool is_opch(uint ch) | |
479 | { | |
480 | return map_isset(op_map, ch); | |
481 | } | |
482 | ||
483 | ||
484 | static int scan_op(Token *tok, Tokenizer *tokz, int c) | |
485 | { | |
486 | int c2; | |
487 | int op=-1; | |
488 | ||
489 | /* Quickly check it is an operator character */ | |
490 | if(!is_opch(c)) | |
491 | return E_TOKZ_INVALID_CHAR; | |
492 | ||
493 | switch(c){ | |
494 | case '+': | |
495 | case '-': | |
496 | case '*': | |
497 | /* case '/': Checked elsewhere */ | |
498 | case '%': | |
499 | case '^': | |
500 | case '!': | |
501 | case '=': | |
502 | case '<': | |
503 | case '>': | |
504 | c2=GETCH(); | |
505 | if(c2=='='){ | |
506 | op=c|(c2<<8); | |
507 | }else if(c2==c && (c2!='%' && c2!='!' && c2!='*')){ | |
508 | if(c=='<' || c=='>'){ | |
509 | int c3=GETCH(); | |
510 | if(c3=='='){ | |
511 | op=c|(c2<<8)|(c3<<16); | |
512 | }else{ | |
513 | UNGETCH(c3); | |
514 | op=c|(c2<<8); | |
515 | } | |
516 | }else{ | |
517 | op=c|(c2<<8); | |
518 | } | |
519 | }else{ | |
520 | UNGETCH(c2); | |
521 | op=c; | |
522 | } | |
523 | break; | |
524 | ||
525 | /* It is already known that it is a operator so these are not needed | |
526 | case ':': | |
527 | case '~': | |
528 | case '?': | |
529 | case '.': | |
530 | case ';'; | |
531 | case '{': | |
532 | case '}': | |
533 | case '@': | |
534 | case '|': | |
535 | case '&': | |
536 | */ | |
537 | default: | |
538 | op=c; | |
539 | } | |
540 | ||
541 | TOK_SET_OP(tok, op); | |
542 | ||
543 | return 0; | |
544 | } | |
545 | ||
546 | ||
547 | /* */ | |
548 | ||
549 | ||
21 | 550 | void tokz_warn(const Tokenizer *tokz, int line, const char *fmt, ...) |
551 | { | |
552 | va_list args; | |
553 | ||
554 | va_start(args, fmt); | |
555 | ||
556 | if(tokz!=NULL) | |
557 | warn_obj_line_v(tokz->name, line, fmt, args); | |
558 | else | |
559 | warn(fmt, args); | |
560 | ||
561 | va_end(args); | |
562 | } | |
563 | ||
564 | ||
0 | 565 | void tokz_warn_error(const Tokenizer *tokz, int line, int e) |
566 | { | |
567 | if(e==E_TOKZ_UNEXPECTED_EOF) | |
568 | line=0; | |
569 | ||
21 | 570 | if(e<0) |
571 | tokz_warn(tokz, line, "%s", strerror(-e)); | |
572 | else | |
573 | tokz_warn(tokz, line, "%s", TR(errors[e])); | |
0 | 574 | } |
575 | ||
576 | ||
577 | bool tokz_get_token(Tokenizer *tokz, Token *tok) | |
578 | { | |
579 | int c, c2, e; | |
580 | ||
1 | 581 | assert(tokz->file!=NULL); |
0 | 582 | |
583 | tok_free(tok); | |
584 | ||
2 | 585 | if(!TOK_IS_INVALID(&(tokz->ungettok))){ |
586 | *tok=tokz->ungettok; | |
587 | tokz->ungettok.type=TOK_INVALID; | |
588 | return TRUE; | |
589 | } | |
590 | ||
0 | 591 | while(1){ |
592 | ||
593 | e=0; | |
594 | ||
595 | do{ | |
596 | c=GETCH(); | |
597 | }while(c!='\n' && c!=EOF && isspace(c)); | |
598 | ||
599 | tok->line=tokz->line; | |
600 | ||
601 | switch(c){ | |
602 | case EOF: | |
603 | TOK_SET_OP(tok, OP_EOF); | |
604 | return TRUE; | |
605 | ||
606 | case '\n': | |
607 | INC_LINE(); | |
608 | ||
609 | if(tokz->flags&TOKZ_IGNORE_NEXTLINE) | |
610 | continue; | |
611 | ||
612 | TOK_SET_OP(tok, OP_NEXTLINE); | |
613 | ||
614 | return TRUE; | |
615 | ||
616 | case '\\': | |
617 | do{ | |
618 | c=GETCH(); | |
619 | if(c==EOF){ | |
620 | TOK_SET_OP(tok, OP_EOF); | |
621 | return FALSE; | |
622 | } | |
2 | 623 | if(!isspace(c) && e==0){ |
624 | e=E_TOKZ_EOL_EXPECTED; | |
625 | tokz_warn_error(tokz, tokz->line, e); | |
626 | if(!(tokz->flags&TOKZ_ERROR_TOLERANT)) | |
627 | return FALSE; | |
0 | 628 | } |
629 | }while(c!='\n'); | |
630 | ||
631 | INC_LINE(); | |
632 | continue; | |
633 | ||
634 | case '#': | |
635 | if(tokz->flags&TOKZ_READ_COMMENTS){ | |
636 | e=scan_line_comment(tok, tokz); | |
637 | break; | |
638 | }else if((e=skip_line_comment(tokz))){ | |
639 | break; | |
640 | } | |
641 | ||
642 | continue; | |
643 | ||
644 | case '/': | |
2 | 645 | c2=GETCH(); |
646 | ||
647 | if(c2=='='){ | |
648 | TOK_SET_OP(tok, OP_AS_DIV); | |
649 | return TRUE; | |
0 | 650 | } |
651 | ||
2 | 652 | if(c2!='*'){ |
653 | UNGETCH(c2); | |
654 | TOK_SET_OP(tok, OP_DIV); | |
655 | return TRUE; | |
656 | } | |
657 | ||
658 | if(tokz->flags&TOKZ_READ_COMMENTS){ | |
659 | e=scan_c_comment(tok, tokz); | |
660 | break; | |
661 | }else if((e=skip_c_comment(tokz))){ | |
662 | break; | |
663 | } | |
664 | ||
665 | continue; | |
666 | ||
0 | 667 | case '\"': |
668 | e=scan_string(tok, tokz, TRUE); | |
669 | break; | |
670 | ||
671 | case '\'': | |
672 | e=scan_char(tok, tokz); | |
673 | break; | |
674 | ||
675 | default: | |
676 | if(('0'<=c && c<='9') || c=='-' || c=='+'){ | |
677 | e=scan_number(tok, tokz, c); | |
678 | break; | |
679 | } | |
680 | ||
681 | if(START_IDENT(c)) | |
682 | e=scan_identifier(tok, tokz, c); | |
683 | else | |
684 | e=scan_op(tok, tokz, c); | |
685 | } | |
686 | ||
687 | if(!e) | |
688 | return TRUE; | |
689 | ||
690 | tokz_warn_error(tokz, tokz->line, e); | |
691 | return FALSE; | |
692 | } | |
693 | } | |
694 | ||
695 | ||
2 | 696 | void tokz_unget_token(Tokenizer *tokz, Token *tok) |
697 | { | |
698 | tok_free(&(tokz->ungettok)); | |
699 | tokz->ungettok=*tok; | |
700 | tok->type=TOK_INVALID; | |
701 | } | |
702 | ||
703 | ||
1 | 704 | /* |
705 | * File open | |
706 | */ | |
707 | ||
708 | static bool do_tokz_pushf(Tokenizer *tokz) | |
709 | { | |
710 | Tokenizer_FInfo *finfo; | |
711 | ||
712 | finfo=REALLOC_N(tokz->filestack, Tokenizer_FInfo, | |
713 | tokz->filestack_n, tokz->filestack_n+1); | |
714 | ||
715 | if(finfo==NULL) | |
716 | return FALSE; | |
717 | ||
718 | tokz->filestack=finfo; | |
719 | finfo=&(finfo[tokz->filestack_n++]); | |
720 | ||
721 | finfo->file=tokz->file; | |
722 | finfo->name=tokz->name; | |
723 | finfo->line=tokz->line; | |
724 | finfo->ungetc=tokz->ungetc; | |
2 | 725 | finfo->ungettok=tokz->ungettok; |
726 | ||
1 | 727 | return TRUE; |
728 | } | |
729 | ||
730 | ||
14 | 731 | bool tokz_pushf_file(Tokenizer *tokz, FILE *file, const char *fname) |
1 | 732 | { |
14 | 733 | char *fname_copy=NULL; |
734 | ||
1 | 735 | if(file==NULL) |
736 | return FALSE; | |
14 | 737 | |
738 | if(fname!=NULL){ | |
739 | fname_copy=scopy(fname); | |
740 | if(fname_copy==NULL){ | |
1 | 741 | warn_err(); |
742 | return FALSE; | |
743 | } | |
744 | } | |
745 | ||
14 | 746 | if(tokz->file!=NULL){ |
747 | if(!do_tokz_pushf(tokz)){ | |
748 | warn_err(); | |
749 | if(fname_copy!=NULL) | |
750 | free(fname_copy); | |
751 | return FALSE; | |
752 | } | |
753 | } | |
754 | ||
1 | 755 | tokz->file=file; |
14 | 756 | tokz->name=fname_copy; |
1 | 757 | tokz->line=1; |
2 | 758 | tokz->ungetc=-1; |
759 | tokz->ungettok.type=TOK_INVALID; | |
1 | 760 | |
761 | return TRUE; | |
762 | } | |
763 | ||
764 | ||
765 | bool tokz_pushf(Tokenizer *tokz, const char *fname) | |
766 | { | |
767 | FILE *file; | |
0 | 768 | |
769 | file=fopen(fname, "r"); | |
770 | ||
771 | if(file==NULL){ | |
772 | warn_err_obj(fname); | |
1 | 773 | return FALSE; |
0 | 774 | } |
775 | ||
14 | 776 | if(!tokz_pushf_file(tokz, file, fname)){ |
777 | fclose(file); | |
778 | return FALSE; | |
1 | 779 | } |
780 | ||
781 | return TRUE; | |
0 | 782 | } |
783 | ||
784 | ||
1 | 785 | |
786 | static Tokenizer *tokz_create() | |
0 | 787 | { |
788 | Tokenizer*tokz; | |
789 | ||
790 | tokz=ALLOC(Tokenizer); | |
791 | ||
792 | if(tokz==NULL){ | |
793 | warn_err(); | |
794 | return NULL; | |
795 | } | |
796 | ||
1 | 797 | tokz->file=NULL; |
0 | 798 | tokz->name=NULL; |
799 | tokz->line=1; | |
2 | 800 | tokz->ungetc=-1; |
801 | tokz->ungettok.type=TOK_INVALID; | |
0 | 802 | tokz->flags=0; |
803 | tokz->optstack=NULL; | |
804 | tokz->nest_lvl=0; | |
1 | 805 | tokz->filestack_n=0; |
806 | tokz->filestack=NULL; | |
807 | ||
808 | return tokz; | |
809 | } | |
810 | ||
811 | ||
812 | Tokenizer *tokz_open(const char *fname) | |
813 | { | |
814 | Tokenizer *tokz; | |
815 | ||
816 | tokz=tokz_create(); | |
817 | ||
818 | if(!tokz_pushf(tokz, fname)){ | |
819 | free(tokz); | |
820 | return NULL; | |
821 | } | |
822 | ||
823 | return tokz; | |
824 | } | |
825 | ||
826 | ||
14 | 827 | Tokenizer *tokz_open_file(FILE *file, const char *fname) |
1 | 828 | { |
829 | Tokenizer *tokz; | |
830 | ||
831 | tokz=tokz_create(); | |
832 | ||
14 | 833 | if(!tokz_pushf_file(tokz, file, fname)){ |
1 | 834 | free(tokz); |
835 | return NULL; | |
836 | } | |
0 | 837 | |
838 | return tokz; | |
839 | } | |
840 | ||
841 | ||
1 | 842 | /* |
843 | * File close | |
844 | */ | |
845 | ||
846 | static bool do_tokz_popf(Tokenizer *tokz, bool shrink) | |
847 | { | |
848 | Tokenizer_FInfo *finfo; | |
849 | ||
850 | if(tokz->filestack_n<=0) | |
851 | return FALSE; | |
852 | ||
853 | if(tokz->file!=NULL) | |
854 | fclose(tokz->file); | |
855 | if(tokz->name!=NULL) | |
856 | free(tokz->name); | |
857 | ||
858 | finfo=&(tokz->filestack[--tokz->filestack_n]); | |
859 | ||
860 | tokz->file=finfo->file; | |
861 | tokz->name=finfo->name; | |
862 | tokz->line=finfo->line; | |
863 | tokz->ungetc=finfo->ungetc; | |
2 | 864 | tokz->ungettok=finfo->ungettok; |
865 | ||
1 | 866 | if(tokz->filestack_n==0){ |
867 | free(tokz->filestack); | |
868 | tokz->filestack=NULL; | |
869 | }else if(shrink){ | |
870 | finfo=REALLOC_N(tokz->filestack, Tokenizer_FInfo, | |
871 | tokz->filestack_n+1, tokz->filestack_n); | |
872 | if(finfo==NULL) | |
873 | warn_err(); | |
874 | else | |
875 | tokz->filestack=finfo; | |
876 | } | |
877 | ||
878 | return TRUE; | |
879 | } | |
880 | ||
881 | ||
882 | bool tokz_popf(Tokenizer *tokz) | |
883 | { | |
884 | return do_tokz_popf(tokz, TRUE); | |
885 | } | |
886 | ||
887 | ||
0 | 888 | void tokz_close(Tokenizer *tokz) |
889 | { | |
1 | 890 | while(tokz->filestack_n>0) |
891 | do_tokz_popf(tokz, FALSE); | |
892 | ||
0 | 893 | if(tokz->file!=NULL) |
894 | fclose(tokz->file); | |
1 | 895 | if(tokz->name!=NULL) |
896 | free(tokz->name); | |
2 | 897 | tok_free(&(tokz->ungettok)); |
898 | ||
0 | 899 | free(tokz); |
900 | } | |
901 | ||
902 | ||
1 | 903 | |
0 | 904 | /* */ |
905 | ||
906 | ||
907 | void tok_free(Token *tok) | |
908 | { | |
2 | 909 | if(TOK_IS_STRING(tok) || TOK_IS_IDENT(tok) || TOK_IS_COMMENT(tok)){ |
910 | if(TOK_STRING_VAL(tok)!=NULL) | |
911 | free(TOK_STRING_VAL(tok)); | |
912 | } | |
0 | 913 | |
914 | tok->type=TOK_INVALID; | |
915 | } | |
916 | ||
917 | ||
918 | void tok_init(Token *tok) | |
919 | { | |
920 | static Token dummy=TOK_INIT; | |
921 | ||
922 | memcpy(tok, &dummy, sizeof(*tok)); | |
923 | } | |
924 |