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