2 * This is a really stupid C tokenizer. It doesn't do any include
3 * files or anything complex at all. That's the preprocessor.
5 * Copyright (C) 2003 Transmeta Corp.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 int input_stream_nr
= 0;
43 struct stream
*input_streams
;
44 static int input_streams_allocated
;
45 unsigned int tabstop
= 8;
48 #define BUFSIZE (8192)
53 int newline
, whitespace
;
54 struct token
**tokenlist
;
56 unsigned char *buffer
;
59 const char *stream_name(int stream
)
61 if (stream
< 0 || stream
> input_stream_nr
)
62 return "<bad stream>";
63 return input_streams
[stream
].name
;
66 int stream_prev(int stream
)
68 if (stream
< 0 || stream
> input_stream_nr
)
70 stream
= input_streams
[stream
].pos
.stream
;
71 if (stream
> input_stream_nr
)
76 static struct position
stream_pos(stream_t
*stream
)
80 pos
.stream
= stream
->nr
;
81 pos
.newline
= stream
->newline
;
82 pos
.whitespace
= stream
->whitespace
;
83 pos
.pos
= stream
->pos
;
85 pos
.line
= stream
->line
;
93 const char *show_special(int val
)
95 static char buffer
[4];
99 if (val
>= SPECIAL_BASE
)
100 strcpy(buffer
, (char *) combinations
[val
- SPECIAL_BASE
]);
104 const char *show_ident(const struct ident
*ident
)
106 static char buff
[4][256];
112 buffer
= buff
[3 & ++n
];
113 sprintf(buffer
, "%.*s", ident
->len
, ident
->name
);
117 static char *charstr(char *ptr
, unsigned char c
, unsigned char escape
, unsigned char next
)
120 if (c
== escape
|| c
== '\\')
135 return ptr
+ sprintf(ptr
, "%o", c
);
137 return ptr
+ sprintf(ptr
, "%03o", c
);
140 const char *show_string(const struct string
*string
)
142 static char buffer
[4 * MAX_STRING
+ 3];
146 if (!string
|| !string
->length
)
147 return "<bad_string>";
150 for (i
= 0; i
< string
->length
-1; i
++) {
151 const char *p
= string
->data
+ i
;
152 ptr
= charstr(ptr
, p
[0], '"', p
[1]);
159 static const char *show_char(const char *s
, size_t len
, char prefix
, char delim
)
161 static char buffer
[MAX_STRING
+ 4];
173 static const char *quote_char(const char *s
, size_t len
, char prefix
, char delim
)
175 static char buffer
[2*MAX_STRING
+ 6];
183 for (i
= 0; i
< len
; i
++) {
184 if (s
[i
] == '"' || s
[i
] == '\\')
195 const char *show_token(const struct token
*token
)
197 static char buffer
[256];
201 switch (token_type(token
)) {
203 return "syntax error";
206 return "end-of-input";
209 case TOKEN_ZERO_IDENT
:
210 return show_ident(token
->ident
);
213 return token
->number
;
216 return show_special(token
->special
);
219 return show_char(token
->string
->data
,
220 token
->string
->length
- 1, 0, '\'');
221 case TOKEN_CHAR_EMBEDDED_0
... TOKEN_CHAR_EMBEDDED_3
:
222 return show_char(token
->embedded
,
223 token_type(token
) - TOKEN_CHAR
, 0, '\'');
224 case TOKEN_WIDE_CHAR
:
225 return show_char(token
->string
->data
,
226 token
->string
->length
- 1, 'L', '\'');
227 case TOKEN_WIDE_CHAR_EMBEDDED_0
... TOKEN_WIDE_CHAR_EMBEDDED_3
:
228 return show_char(token
->embedded
,
229 token_type(token
) - TOKEN_WIDE_CHAR
, 'L', '\'');
231 return show_char(token
->string
->data
,
232 token
->string
->length
- 1, 0, '"');
233 case TOKEN_WIDE_STRING
:
234 return show_char(token
->string
->data
,
235 token
->string
->length
- 1, 'L', '"');
237 case TOKEN_STREAMBEGIN
:
238 sprintf(buffer
, "<beginning of '%s'>", stream_name(token
->pos
.stream
));
241 case TOKEN_STREAMEND
:
242 sprintf(buffer
, "<end of '%s'>", stream_name(token
->pos
.stream
));
246 sprintf(buffer
, "<untaint>");
249 case TOKEN_ARG_COUNT
:
250 sprintf(buffer
, "<argcnt>");
254 sprintf(buffer
, "unhandled token type '%d' ", token_type(token
));
259 const char *quote_token(const struct token
*token
)
261 static char buffer
[256];
263 switch (token_type(token
)) {
265 return "syntax error";
268 case TOKEN_ZERO_IDENT
:
269 return show_ident(token
->ident
);
272 return token
->number
;
275 return show_special(token
->special
);
278 return quote_char(token
->string
->data
,
279 token
->string
->length
- 1, 0, '\'');
280 case TOKEN_CHAR_EMBEDDED_0
... TOKEN_CHAR_EMBEDDED_3
:
281 return quote_char(token
->embedded
,
282 token_type(token
) - TOKEN_CHAR
, 0, '\'');
283 case TOKEN_WIDE_CHAR
:
284 return quote_char(token
->string
->data
,
285 token
->string
->length
- 1, 'L', '\'');
286 case TOKEN_WIDE_CHAR_EMBEDDED_0
... TOKEN_WIDE_CHAR_EMBEDDED_3
:
287 return quote_char(token
->embedded
,
288 token_type(token
) - TOKEN_WIDE_CHAR
, 'L', '\'');
290 return quote_char(token
->string
->data
,
291 token
->string
->length
- 1, 0, '"');
292 case TOKEN_WIDE_STRING
:
293 return quote_char(token
->string
->data
,
294 token
->string
->length
- 1, 'L', '"');
296 sprintf(buffer
, "unhandled token type '%d' ", token_type(token
));
301 #define HASHED_INPUT_BITS (6)
302 #define HASHED_INPUT (1 << HASHED_INPUT_BITS)
303 #define HASH_PRIME 0x9e370001UL
305 static int input_stream_hashes
[HASHED_INPUT
] = { [0 ... HASHED_INPUT
-1] = -1 };
307 int *hash_stream(const char *name
)
312 while ((c
= *name
++) != 0)
313 hash
= (hash
+ (c
<< 4) + (c
>> 4)) * 11;
316 hash
>>= 32 - HASHED_INPUT_BITS
;
317 return input_stream_hashes
+ hash
;
320 int init_stream(const struct position
*pos
, const char *name
, int fd
, const char **next_path
)
322 int stream
= input_stream_nr
, *hash
;
323 struct stream
*current
;
325 if (stream
>= input_streams_allocated
) {
326 int newalloc
= stream
* 4 / 3 + 10;
327 input_streams
= realloc(input_streams
, newalloc
* sizeof(struct stream
));
329 die("Unable to allocate more streams space");
330 input_streams_allocated
= newalloc
;
332 current
= input_streams
+ stream
;
333 memset(current
, 0, sizeof(*current
));
334 current
->name
= name
;
336 current
->next_path
= next_path
;
337 current
->path
= NULL
;
338 current
->constant
= CONSTANT_FILE_MAYBE
;
342 current
->pos
.stream
= -1;
343 input_stream_nr
= stream
+1;
344 hash
= hash_stream(name
);
345 current
->next_stream
= *hash
;
350 static struct token
* alloc_token(stream_t
*stream
)
352 struct token
*token
= __alloc_token(0);
353 token
->pos
= stream_pos(stream
);
358 * Argh... That was surprisingly messy - handling '\r' complicates the
361 static int nextchar_slow(stream_t
*stream
)
363 int offset
= stream
->offset
;
364 int size
= stream
->size
;
366 int spliced
= 0, had_cr
, had_backslash
;
369 had_cr
= had_backslash
= 0;
372 if (offset
>= size
) {
375 size
= read(stream
->fd
, stream
->buffer
, BUFSIZE
);
379 stream
->offset
= offset
= 0;
382 c
= stream
->buffer
[offset
++];
392 if (!had_backslash
) {
395 stream
->pos
+= tabstop
- stream
->pos
% tabstop
;
420 stream
->offset
= offset
;
435 if (stream
->pos
& Wnewline_eof
)
436 warning(stream_pos(stream
), "no newline at end of file");
438 warning(stream_pos(stream
), "backslash-newline at end of file");
443 * We want that as light as possible while covering all normal cases.
444 * Slow path (including the logics with line-splicing and EOF sanity
445 * checks) is in nextchar_slow().
447 static inline int nextchar(stream_t
*stream
)
449 int offset
= stream
->offset
;
451 if (offset
< stream
->size
) {
452 int c
= stream
->buffer
[offset
++];
453 static const char special
[256] = {
454 ['\t'] = 1, ['\r'] = 1, ['\n'] = 1, ['\\'] = 1
457 stream
->offset
= offset
;
462 return nextchar_slow(stream
);
465 struct token eof_token_entry
;
467 static struct token
*mark_eof(stream_t
*stream
)
471 end
= alloc_token(stream
);
472 eof_token_entry
.pos
= end
->pos
;
473 token_type(end
) = TOKEN_STREAMEND
;
474 end
->pos
.newline
= 1;
476 eof_token_entry
.next
= &eof_token_entry
;
477 eof_token_entry
.pos
.newline
= 1;
479 end
->next
= &eof_token_entry
;
480 *stream
->tokenlist
= end
;
481 stream
->tokenlist
= NULL
;
485 static void add_token(stream_t
*stream
)
487 struct token
*token
= stream
->token
;
489 stream
->token
= NULL
;
491 *stream
->tokenlist
= token
;
492 stream
->tokenlist
= &token
->next
;
495 static void drop_token(stream_t
*stream
)
497 stream
->newline
|= stream
->token
->pos
.newline
;
498 stream
->whitespace
|= stream
->token
->pos
.whitespace
;
499 stream
->token
= NULL
;
512 static const char cclass
[257] = {
513 ['0' + 1 ... '9' + 1] = Digit
| Hex
,
514 ['A' + 1 ... 'D' + 1] = Letter
| Hex
,
515 ['E' + 1] = Letter
| Hex
| Exp
, /* E<exp> */
516 ['F' + 1] = Letter
| Hex
,
517 ['G' + 1 ... 'O' + 1] = Letter
,
518 ['P' + 1] = Letter
| Exp
, /* P<exp> */
519 ['Q' + 1 ... 'Z' + 1] = Letter
,
520 ['a' + 1 ... 'd' + 1] = Letter
| Hex
,
521 ['e' + 1] = Letter
| Hex
| Exp
, /* e<exp> */
522 ['f' + 1] = Letter
| Hex
,
523 ['g' + 1 ... 'o' + 1] = Letter
,
524 ['p' + 1] = Letter
| Exp
, /* p<exp> */
525 ['q' + 1 ... 'z' + 1] = Letter
,
527 ['.' + 1] = Dot
| ValidSecond
,
528 ['=' + 1] = ValidSecond
,
529 ['+' + 1] = ValidSecond
,
530 ['-' + 1] = ValidSecond
,
531 ['>' + 1] = ValidSecond
,
532 ['<' + 1] = ValidSecond
,
533 ['&' + 1] = ValidSecond
,
534 ['|' + 1] = ValidSecond
,
535 ['#' + 1] = ValidSecond
,
545 * pp-number identifier-nodigit
552 static int get_one_number(int c
, int next
, stream_t
*stream
)
555 static char buffer
[4095];
556 char *p
= buffer
, *buffer_end
= buffer
+ sizeof (buffer
);
560 long class = cclass
[next
+ 1];
561 if (!(class & (Dot
| Digit
| Letter
)))
565 next
= nextchar(stream
);
567 if (next
== '-' || next
== '+') {
570 next
= nextchar(stream
);
575 if (p
== buffer_end
) {
576 sparse_error(stream_pos(stream
), "number token exceeds %td characters",
577 buffer_end
- buffer
);
578 // Pretend we saw just "1".
584 token
= stream
->token
;
585 token_type(token
) = TOKEN_NUMBER
;
586 token
->number
= xmemdup(buffer
, p
- buffer
);
592 static int eat_string(int next
, stream_t
*stream
, enum token_type type
)
594 static char buffer
[MAX_STRING
];
595 struct string
*string
;
596 struct token
*token
= stream
->token
;
600 char delim
= type
< TOKEN_STRING
? '\'' : '"';
602 for (escape
= 0; escape
|| next
!= delim
; next
= nextchar(stream
)) {
603 if (len
< MAX_STRING
)
607 warning(stream_pos(stream
),
608 "missing terminating %c character", delim
);
609 /* assume delimiter is lost */
613 warning(stream_pos(stream
),
614 "End of file in middle of string");
618 if (want_hex
&& !(cclass
[next
+ 1] & Hex
))
619 warning(stream_pos(stream
),
620 "\\x used with no following hex digits");
622 escape
= next
== '\\';
625 want_hex
= next
== 'x';
629 warning(stream_pos(stream
),
630 "\\x used with no following hex digits");
631 if (len
> MAX_STRING
) {
632 warning(stream_pos(stream
), "string too long (%d bytes, %d bytes max)", len
, MAX_STRING
);
635 if (delim
== '\'' && len
&& len
<= 4) {
636 token_type(token
) = type
+ len
;
637 memset(buffer
+ len
, '\0', 4 - len
);
638 memcpy(token
->embedded
, buffer
, 4);
640 token_type(token
) = type
;
641 string
= __alloc_string(len
+1);
642 memcpy(string
->data
, buffer
, len
);
643 string
->data
[len
] = '\0';
644 string
->length
= len
+1;
645 token
->string
= string
;
649 token
= stream
->token
;
651 return nextchar(stream
);
654 static int drop_stream_eoln(stream_t
*stream
)
658 switch (nextchar(stream
)) {
662 return nextchar(stream
);
667 static int drop_stream_comment(stream_t
*stream
)
672 newline
= stream
->newline
;
674 next
= nextchar(stream
);
678 warning(stream_pos(stream
), "End of file in the middle of a comment");
681 next
= nextchar(stream
);
682 if (curr
== '*' && next
== '/')
685 stream
->newline
= newline
;
686 return nextchar(stream
);
689 unsigned char combinations
[][4] = COMBINATION_STRINGS
;
691 #define NR_COMBINATIONS (SPECIAL_ARG_SEPARATOR - SPECIAL_BASE)
693 /* hash function for two-character punctuators - all give unique values */
694 #define special_hash(c0, c1) (((c0*8+c1*2)+((c0*8+c1*2)>>5))&31)
697 * note that we won't get false positives - special_hash(0,0) is 0 and
698 * entry 0 is filled (by +=), so all the missing ones are OK.
700 static unsigned char hash_results
[32][2] = {
701 #define RES(c0, c1) [special_hash(c0, c1)] = {c0, c1}
702 RES('+', '='), /* 00 */
703 RES('/', '='), /* 01 */
704 RES('^', '='), /* 05 */
705 RES('&', '&'), /* 07 */
706 RES('#', '#'), /* 08 */
707 RES('<', '<'), /* 0a */
708 RES('<', '='), /* 0c */
709 RES('!', '='), /* 0e */
710 RES('%', '='), /* 0f */
711 RES('-', '-'), /* 10 */
712 RES('-', '='), /* 11 */
713 RES('-', '>'), /* 13 */
714 RES('=', '='), /* 15 */
715 RES('&', '='), /* 17 */
716 RES('*', '='), /* 18 */
717 RES('.', '.'), /* 1a */
718 RES('+', '+'), /* 1b */
719 RES('|', '='), /* 1c */
720 RES('>', '='), /* 1d */
721 RES('|', '|'), /* 1e */
722 RES('>', '>') /* 1f */
725 static int code
[32] = {
726 #define CODE(c0, c1, value) [special_hash(c0, c1)] = value
727 CODE('+', '=', SPECIAL_ADD_ASSIGN
), /* 00 */
728 CODE('/', '=', SPECIAL_DIV_ASSIGN
), /* 01 */
729 CODE('^', '=', SPECIAL_XOR_ASSIGN
), /* 05 */
730 CODE('&', '&', SPECIAL_LOGICAL_AND
), /* 07 */
731 CODE('#', '#', SPECIAL_HASHHASH
), /* 08 */
732 CODE('<', '<', SPECIAL_LEFTSHIFT
), /* 0a */
733 CODE('<', '=', SPECIAL_LTE
), /* 0c */
734 CODE('!', '=', SPECIAL_NOTEQUAL
), /* 0e */
735 CODE('%', '=', SPECIAL_MOD_ASSIGN
), /* 0f */
736 CODE('-', '-', SPECIAL_DECREMENT
), /* 10 */
737 CODE('-', '=', SPECIAL_SUB_ASSIGN
), /* 11 */
738 CODE('-', '>', SPECIAL_DEREFERENCE
), /* 13 */
739 CODE('=', '=', SPECIAL_EQUAL
), /* 15 */
740 CODE('&', '=', SPECIAL_AND_ASSIGN
), /* 17 */
741 CODE('*', '=', SPECIAL_MUL_ASSIGN
), /* 18 */
742 CODE('.', '.', SPECIAL_DOTDOT
), /* 1a */
743 CODE('+', '+', SPECIAL_INCREMENT
), /* 1b */
744 CODE('|', '=', SPECIAL_OR_ASSIGN
), /* 1c */
745 CODE('>', '=', SPECIAL_GTE
), /* 1d */
746 CODE('|', '|', SPECIAL_LOGICAL_OR
), /* 1e */
747 CODE('>', '>', SPECIAL_RIGHTSHIFT
) /* 1f */
751 static int get_one_special(int c
, stream_t
*stream
)
756 next
= nextchar(stream
);
759 * Check for numbers, strings, character constants, and comments
763 if (next
>= '0' && next
<= '9')
764 return get_one_number(c
, next
, stream
);
767 return eat_string(next
, stream
, TOKEN_STRING
);
769 return eat_string(next
, stream
, TOKEN_CHAR
);
772 return drop_stream_eoln(stream
);
774 return drop_stream_comment(stream
);
778 * Check for combinations
781 if (cclass
[next
+ 1] & ValidSecond
) {
782 i
= special_hash(c
, next
);
783 if (hash_results
[i
][0] == c
&& hash_results
[i
][1] == next
) {
785 next
= nextchar(stream
);
786 if (value
>= SPECIAL_LEFTSHIFT
&&
787 next
== "==."[value
- SPECIAL_LEFTSHIFT
]) {
789 next
= nextchar(stream
);
795 token
= stream
->token
;
796 token_type(token
) = TOKEN_SPECIAL
;
797 token
->special
= value
;
802 #define IDENT_HASH_BITS (13)
803 #define IDENT_HASH_SIZE (1<<IDENT_HASH_BITS)
804 #define IDENT_HASH_MASK (IDENT_HASH_SIZE-1)
806 #define ident_hash_init(c) (c)
807 #define ident_hash_add(oldhash,c) ((oldhash)*11 + (c))
808 #define ident_hash_end(hash) ((((hash) >> IDENT_HASH_BITS) + (hash)) & IDENT_HASH_MASK)
810 static struct ident
*hash_table
[IDENT_HASH_SIZE
];
811 static int ident_hit
, ident_miss
, idents
;
813 void show_identifier_stats(void)
816 int distribution
[100];
818 fprintf(stderr
, "identifiers: %d hits, %d misses\n",
819 ident_hit
, ident_miss
);
821 for (i
= 0; i
< 100; i
++)
824 for (i
= 0; i
< IDENT_HASH_SIZE
; i
++) {
825 struct ident
* ident
= hash_table
[i
];
834 distribution
[count
]++;
837 for (i
= 0; i
< 100; i
++) {
839 fprintf(stderr
, "%2d: %d buckets\n", i
, distribution
[i
]);
843 struct ident
*alloc_ident(const char *name
, int len
)
845 struct ident
*ident
= __alloc_ident(len
);
846 ident
->symbols
= NULL
;
849 memcpy(ident
->name
, name
, len
);
853 static struct ident
* insert_hash(struct ident
*ident
, unsigned long hash
)
855 ident
->next
= hash_table
[hash
];
856 hash_table
[hash
] = ident
;
861 static struct ident
*create_hashed_ident(const char *name
, int len
, unsigned long hash
)
866 p
= &hash_table
[hash
];
867 while ((ident
= *p
) != NULL
) {
868 if (ident
->len
== (unsigned char) len
) {
869 if (strncmp(name
, ident
->name
, len
) != 0)
879 ident
= alloc_ident(name
, len
);
887 static unsigned long hash_name(const char *name
, int len
)
890 const unsigned char *p
= (const unsigned char *)name
;
892 hash
= ident_hash_init(*p
++);
894 unsigned int i
= *p
++;
895 hash
= ident_hash_add(hash
, i
);
897 return ident_hash_end(hash
);
900 struct ident
*hash_ident(struct ident
*ident
)
902 return insert_hash(ident
, hash_name(ident
->name
, ident
->len
));
905 struct ident
*built_in_ident(const char *name
)
907 int len
= strlen(name
);
908 return create_hashed_ident(name
, len
, hash_name(name
, len
));
911 struct token
*built_in_token(int stream
, struct ident
*ident
)
915 token
= __alloc_token(0);
916 token
->pos
.stream
= stream
;
917 token_type(token
) = TOKEN_IDENT
;
918 token
->ident
= ident
;
922 static int get_one_identifier(int c
, stream_t
*stream
)
931 hash
= ident_hash_init(c
);
934 next
= nextchar(stream
);
935 if (!(cclass
[next
+ 1] & (Letter
| Digit
)))
937 if (len
>= sizeof(buf
))
939 hash
= ident_hash_add(hash
, next
);
943 if (cclass
[next
+ 1] & Quote
) {
944 if (len
== 1 && (buf
[0] == 'L' || buf
[0] == 'u')) {
946 return eat_string(nextchar(stream
), stream
,
949 return eat_string(nextchar(stream
), stream
,
953 hash
= ident_hash_end(hash
);
954 ident
= create_hashed_ident(buf
, len
, hash
);
957 token
= stream
->token
;
958 token_type(token
) = TOKEN_IDENT
;
959 token
->ident
= ident
;
964 static int get_one_token(int c
, stream_t
*stream
)
966 long class = cclass
[c
+ 1];
968 return get_one_number(c
, nextchar(stream
), stream
);
970 return get_one_identifier(c
, stream
);
971 return get_one_special(c
, stream
);
974 static struct token
*setup_stream(stream_t
*stream
, int idx
, int fd
,
975 unsigned char *buf
, unsigned int buf_size
)
982 stream
->whitespace
= 0;
985 stream
->token
= NULL
;
988 stream
->size
= buf_size
;
989 stream
->buffer
= buf
;
991 begin
= alloc_token(stream
);
992 token_type(begin
) = TOKEN_STREAMBEGIN
;
993 stream
->tokenlist
= &begin
->next
;
997 static struct token
*tokenize_stream(stream_t
*stream
)
999 int c
= nextchar(stream
);
1002 struct token
*token
= alloc_token(stream
);
1003 stream
->token
= token
;
1004 stream
->newline
= 0;
1005 stream
->whitespace
= 0;
1006 c
= get_one_token(c
, stream
);
1009 stream
->whitespace
= 1;
1010 c
= nextchar(stream
);
1012 return mark_eof(stream
);
1015 struct token
* tokenize_buffer(void *buffer
, unsigned long size
, struct token
**endtoken
)
1018 struct token
*begin
;
1020 begin
= setup_stream(&stream
, 0, -1, buffer
, size
);
1021 *endtoken
= tokenize_stream(&stream
);
1025 struct token
* tokenize(const struct position
*pos
, const char *name
, int fd
, struct token
*endtoken
, const char **next_path
)
1027 struct token
*begin
, *end
;
1029 unsigned char buffer
[BUFSIZE
];
1032 idx
= init_stream(pos
, name
, fd
, next_path
);
1034 // info(endtoken->pos, "File %s is const", name);
1038 begin
= setup_stream(&stream
, idx
, fd
, buffer
, 0);
1039 end
= tokenize_stream(&stream
);
1041 end
->next
= endtoken
;