Initial commit
[cgperf.git] / input.c
bloba6784a05e9fce47bb13e9e80edcbed10cde77887
1 #ifndef CGPERF_INPUT_C
2 #define CGPERF_INPUT_C
3 #include <stdbool.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "globals.h"
8 #include "keyword.h"
9 #include "input.h"
10 #include "getline.h"
11 #include "options.h"
12 #include "keyword.h"
13 #include "keyword_list.h"
14 /*------------------------------------------------------------------------------------------------*/
15 #include "namespace/globals.h"
16 #include "namespace/input.h"
17 #include "namespace/input.c"
18 #include "namespace/keyword.h"
19 #include "namespace/getline.h"
20 #include "namespace/options.h"
21 #include "namespace/keyword.h"
22 #include "namespace/keyword_list.h"
23 /*------------------------------------------------------------------------------------------------*/
24 /*{{{ local */
25 /*{{{ pretty_input_file_name */
26 /* returns a pretty representation of the input file name, for error and warning messages */
27 static u8 *pretty_input_file_name(void)
29 u8 *fn;
31 fn = options->input_file_name;
32 if (fn != 0)
33 return fn;
34 else
35 return "(standard input)";
36 }/*}}}*/
37 /*{{{ is_define_declaration */
39 * Tests if the given line contains a "%define DECL ARG" declaration. If yes, it sets *ARGP to the
40 * argument, and returns true. Otherwise, it returns false.
42 static bool is_define_declaration(u8 *line, u8 *line_end, u32 lineno, u8 *decl, u8 **argp)
44 u8 *d;
45 u8 *arg;
46 u8 *p;
47 /* skip '%' */
48 ++line;
49 /* skip "define" */
51 u8 *d;
52 d = "define";
53 loop {
54 if (*d == 0)
55 break;
56 if (!(line < line_end))
57 return false;
58 if (!(*line == *d))
59 return false;
60 ++line;
61 ++d;
63 if (!(line < line_end && (*line == ' ' || *line == '\t')))
64 return false;
66 /* skip whitespace */
67 loop {
68 if (line >= line_end || !(*line == ' ' || *line == '\t'))
69 break;
70 ++line;
72 /* skip DECL */
73 d = decl;
74 loop {
75 if (*d == 0)
76 break;
77 if (!(line < line_end))
78 return false;
79 if (!(*line == *d || (*d == '-' && *line == '_')))
80 return false;
81 ++line;
82 ++d;
84 if (line < line_end
85 && ((*line >= 'A' && *line <= 'Z')
86 || (*line >= 'a' && *line <= 'z')
87 || *line == '-' || *line == '_'))
88 return false;
89 /* OK, found DECL */
90 /* skip whitespace */
91 if (!(line < line_end && (*line == ' ' || *line == '\t'))) {
92 fprintf (stderr, "%s:%u: missing argument in %%define %s ARG declaration.\n", pretty_input_file_name(), lineno, decl);
93 exit(1);
95 loop {
96 ++line;
97 if (line >= line_end || !(*line == ' ' || *line == '\t'))
98 break;
100 /* The next word is the argument */
101 arg = calloc(line_end - line + 1, sizeof(u8));
102 p = arg;
103 loop {
104 if (line >= line_end || (*line == ' ' || *line == '\t' || *line == '\n'))
105 break;
106 *p++ = *line++;
108 *p = '\0';
109 /* skip whitespace */
110 loop {
111 if (line >= line_end || !(*line == ' ' || *line == '\t'))
112 break;
113 ++line;
115 /* expect end of line */
116 if (line < line_end && *line != '\n') {
117 fprintf(stderr, "%s:%u: junk after declaration\n", pretty_input_file_name(), lineno);
118 exit(1);
120 *argp = arg;
121 return true;
122 }/*}}}*/
123 /*{{{ is_declaration */
124 /* returns true if the given line contains a "%DECL" declaration */
125 static bool is_declaration(u8 *line, u8 *line_end, u32 lineno, u8 *decl)
127 u8 *d;
128 /* skip '%' */
129 ++line;
130 /* skip DECL */
131 d = decl;
132 loop {
133 if (*d == 0)
134 break;
135 if (!(line < line_end))
136 return false;
137 if (!(*line == *d || (*d == '-' && *line == '_')))
138 return false;
139 ++line;
140 ++d;
142 if (line < line_end
143 && ((*line >= 'A' && *line <= 'Z')
144 || (*line >= 'a' && *line <= 'z')
145 || *line == '-' || *line == '_'))
146 return false;
147 /* OK, found DECL. */
148 /* skip whitespace */
149 loop {
150 if (line >= line_end || !(*line == ' ' || *line == '\t'))
151 break;
152 ++line;
154 /* expect end of line */
155 if (line < line_end && *line != '\n') {
156 fprintf(stderr, "%s:%u: junk after declaration\n", pretty_input_file_name(), lineno);
157 exit(1);
159 return true;
160 }/*}}}*/
161 /*{{{ is_declaration_with_arg */
163 * Tests if the given line contains a "%DECL=ARG" declaration. If yes, it sets *ARGP to the
164 * argument, and returns true. Otherwise, it returns false
166 static bool is_declaration_with_arg(u8 *line, u8 *line_end, u32 lineno, u8 *decl, u8 **argp)
168 u8 *d;
169 u8 *arg;
170 u8 *p;
171 /* skip '%' */
172 ++line;
174 /* skip DECL */
175 d = decl;
176 loop {
177 if (*d == 0)
178 break;
179 if (!(line < line_end))
180 return false;
181 if (!(*line == *d || (*d == '-' && *line == '_')))
182 return false;
183 ++line;
184 ++d;
186 if (line < line_end
187 && ((*line >= 'A' && *line <= 'Z')
188 || (*line >= 'a' && *line <= 'z')
189 || *line == '-' || *line == '_'))
190 return false;
191 /* OK, found DECL */
192 /* skip '=' */
193 if (!(line < line_end && *line == '=')) {
194 fprintf(stderr, "%s:%u: missing argument in %%%s=ARG declaration.\n", pretty_input_file_name(), lineno, decl);
195 exit(1);
197 ++line;
198 /* the next word is the argument */
199 arg = calloc(line_end - line + 1, sizeof(u8));
200 p = arg;
201 loop {
202 if (line >= line_end || (*line == ' ' || *line == '\t' || *line == '\n'))
203 break;
204 *p++ = *line++;
206 *p = '\0';
207 /* skip whitespace */
208 loop {
209 if (line >= line_end || !(*line == ' ' || *line == '\t'))
210 break;
211 ++line;
213 /* expect end of line */
214 if (line < line_end && *line != '\n') {
215 fprintf(stderr, "%s:%u: junk after declaration\n", pretty_input_file_name(), lineno);
216 exit(1);
218 *argp = arg;
219 return true;
220 }/*}}}*/
221 /*}}} local -- END */
222 /*{{{ input_new */
223 static struct Input *input_new(FILE *stream)
225 struct Input *t;
227 t = calloc(1, sizeof(*t));
228 t->stream = stream;
229 return t;
230 }/*}}}*/
231 /*{{{ input_del */
232 static void input_del(struct Input *t)
234 free(t->return_type);
235 free(t->struct_tag);
236 free(t->struct_decl);
237 free(t);
238 }/*}}}*/
239 /*{{{ input_read_input */
240 static void input_read(struct Input *t)
242 /*{{{ documentation
243 The input file has the following structure:
244 DECLARATIONS
246 KEYWORDS
248 ADDITIONAL_CODE
249 Since the DECLARATIONS and the ADDITIONAL_CODE sections are optional,
250 we have to read the entire file in the case there is only one %%
251 separator line, in order to determine whether the structure is
252 DECLARATIONS
254 KEYWORDS
256 KEYWORDS
258 ADDITIONAL_CODE
259 When the option -t is given or when the first section contains
260 declaration lines starting with %, we go for the first interpretation,
261 otherwise for the second interpretation. }}}*/
262 u8 *input;
263 u32 input_size;
264 s32 input_length;
265 u8 *input_end;
267 u8 *declarations;
268 u8 *declarations_end;
269 u8 *keywords;
270 u8 *keywords_end;
271 u32 keywords_lineno;
273 input = 0;
274 input_size = 0;
275 input_length = get_delim(&input, &input_size, EOF, t->stream);
276 if (input_length < 0) {
277 if (ferror(t->stream))
278 fprintf(stderr, "%s: error while reading input file\n", pretty_input_file_name());
279 else
280 fprintf(stderr, "%s: The input file is empty!\n", pretty_input_file_name());
281 exit(1);
284 * Convert CR/LF line terminators (Windows) to LF line terminators (Unix). GCC 3.3 and
285 * newer support CR/LF line terminators in C sources on Unix, so we do the same.
286 * The so-called "text mode" in stdio on Windows translates CR/LF to \n automatically, but
287 * here we also need this conversion on Unix. As a side effect, on Windows we also parse
288 * CR/CR/LF into a single \n, but this is not a problem
291 u8 *p;
292 u8 *p_end;
293 u8 *q;
295 p = input;
296 p_end = input + input_length;
297 /* converting the initial segment without CRs is a no-op */
298 loop {
299 if (p >= p_end || *p == '\r')
300 break;
301 ++p;
303 /* then start the conversion for real */
304 q = p;
305 loop {
306 if (p >= p_end)
307 break;
308 if (p[0] == '\r' && p + 1 < p_end && p[1] == '\n')
309 ++p;
310 *q++ = *p++;
312 input_length = (s32)(q - input);
315 * We use input_end as a limit, in order to cope with NUL bytes in the input. But note that
316 * one trailing NUL byte has been added after input_end, for convenience
318 input_end = input + input_length;
319 /* break up the input into the three sections */
321 u8 *separator[2];
322 u32 separator_lineno[2];
323 s32 separators;
324 bool has_declarations;
326 separator[0] = 0;
327 separator[1] = 0;
328 separator_lineno[0] = 0;
329 separator_lineno[1] = 0;
330 separators = 0;
332 u32 lineno;
333 u8 *p;
335 lineno = 1;
336 p = input;
337 loop {
338 if (p >= input_end)
339 break;
340 if (p[0] == '%' && p[1] == '%') {
341 separator[separators] = p;
342 separator_lineno[separators] = lineno;
343 ++separators;
344 if (separators == 2)
345 break;
347 ++lineno;
348 p = (u8*)memchr(p, '\n', input_end - p);
349 if (p != 0)
350 ++p;
351 else
352 p = input_end;
355 if (separators == 1) {
356 if (OPTS(TYPE))
357 has_declarations = true;
358 else {
359 u8 *p;
361 has_declarations = false;
362 p = input;
363 loop {
364 if (p >= separator[0])
365 break;
366 if (p[0] == '%') {
367 has_declarations = true;
368 break;
370 p = (u8*)memchr(p, '\n',
371 separator[0] - p);
372 if (p != 0)
373 ++p;
374 else
375 p = separator[0];
378 } else
379 has_declarations = (separators > 0);
380 if (has_declarations) {
381 bool nonempty_line;
382 u8 *p;
384 declarations = input;
385 declarations_end = separator[0];
386 /* give a warning if the separator line is nonempty */
387 nonempty_line = false;
388 p = declarations_end + 2;
389 loop {
390 if (p >= input_end)
391 break;
392 if (*p == '\n') {
393 ++p;
394 break;
396 if (!(*p == ' ' || *p == '\t'))
397 nonempty_line = true;
398 ++p;
400 if (nonempty_line)
401 fprintf(stderr, "%s:%u: warning: junk after %%%% is ignored\n", pretty_input_file_name(), separator_lineno[0]);
402 keywords = p;
403 keywords_lineno = separator_lineno[0] + 1;
404 } else {
405 declarations = 0;
406 declarations_end = 0;
407 keywords = input;
408 keywords_lineno = 1;
410 if (separators > (has_declarations ? 1 : 0)) {
411 keywords_end = separator[separators - 1];
412 t->verbatim_code = separator[separators - 1] + 2;
413 t->verbatim_code_end = input_end;
414 t->verbatim_code_lineno = separator_lineno[separators - 1];
415 } else {
416 keywords_end = input_end;
417 t->verbatim_code = 0;
418 t->verbatim_code_end = 0;
419 t->verbatim_code_lineno = 0;
422 /* parse the declarations section */
423 t->verbatim_declarations = 0;
424 t->verbatim_declarations_end = 0;
425 t->verbatim_declarations_lineno = 0;
426 t->struct_decl = 0;
427 t->struct_decl_lineno = 0;
428 t->return_type = 0;
429 t->struct_tag = 0;
431 u32 lineno;
432 u8 *struct_decl;
433 u32 *struct_decl_linenos;
434 u32 struct_decl_linecount;
435 u8 *line;
437 lineno = 1;
438 struct_decl = NULL;
439 struct_decl_linenos = NULL;
440 struct_decl_linecount = 0;
442 line = declarations;
443 loop {
444 u8 *line_end;
446 if (line >= declarations_end)
447 break;
448 line_end = (u8*)memchr(line, '\n', declarations_end - line);
449 if (line_end != 0)
450 ++line_end;
451 else
452 line_end = declarations_end;
454 if (*line == '%') {
455 if (line[1] == '{') {
456 /* handle %{ */
457 if (t->verbatim_declarations != 0) {
458 fprintf(stderr, "%s:%u:\n%s:%u:only one %%{...%%} section is allowed\n", pretty_input_file_name(), t->verbatim_declarations_lineno, pretty_input_file_name(), lineno);
459 exit(1);
461 t->verbatim_declarations = line + 2;
462 t->verbatim_declarations_lineno = lineno;
463 } else if (line[1] == '}') {
464 /* handle %} */
465 bool nonempty_line;
466 u8 *q;
467 if (t->verbatim_declarations == 0) {
468 fprintf(stderr, "%s:%u: %%} outside of %%{...%%} section\n", pretty_input_file_name(), lineno);
469 exit(1);
471 if (t->verbatim_declarations_end != 0) {
472 fprintf(stderr, "%s:%u: %%{...%%} section already closed\n", pretty_input_file_name(), lineno);
473 exit(1);
475 t->verbatim_declarations_end = line;
476 /* give a warning if the rest of the line is nonempty */
477 nonempty_line = false;
478 q = line + 2;
479 loop {
480 if (q >= line_end)
481 break;
482 if (*q == '\n') {
483 ++q;
484 break;
486 if (!(*q == ' ' || *q == '\t'))
487 nonempty_line = true;
488 ++q;
490 if (nonempty_line)
491 fprintf(stderr, "%s:%u: warning: junk after %%} is ignored\n", pretty_input_file_name(), lineno);
492 } else if (t->verbatim_declarations != 0
493 && t->verbatim_declarations_end == 0) {
494 fprintf (stderr, "%s:%u: warning: %% directives are ignored" " inside the %%{...%%} section\n", pretty_input_file_name(), lineno);
495 } else {
496 u8 *arg;
498 #define OPT_SET(x) options->option_word |= OPTS_##x
499 if (is_declaration_with_arg(line, line_end, lineno, "delimiters", &arg))
500 opts_set_delimiters(options, arg);
501 else
503 if (is_declaration(line, line_end, lineno, "struct-type"))
504 OPT_SET(TYPE);
505 else
507 if (is_declaration(line, line_end, lineno, "ignore-case"))
508 OPT_SET(UPPERLOWER);
509 else
511 if (is_declaration_with_arg(line, line_end, lineno, "language", &arg))
512 opts_set_language(options, arg);
513 else
515 if (is_define_declaration(line, line_end, lineno, "slot-name", &arg))
516 opts_set_slot_name(options, arg);
517 else
519 if (is_define_declaration(line, line_end, lineno, "initializer-suffix", &arg))
520 opts_set_initializer_suffix(options, arg);
521 else
523 if (is_define_declaration(line, line_end, lineno, "hash-function-name", &arg))
524 opts_set_hash_name(options, arg);
525 else
527 if (is_define_declaration(line, line_end, lineno, "lookup-function-name", &arg))
528 opts_set_function_name(options, arg);
529 else
531 if (is_define_declaration(line, line_end, lineno, "class-name", &arg))
532 opts_set_class_name(options, arg);
533 else
535 if (is_declaration(line, line_end, lineno, "7bit"))
536 OPT_SET(SEVENBIT);
537 else
539 if (is_declaration(line, line_end, lineno, "compare-lengths"))
540 OPT_SET(LENTABLE);
541 else
543 if (is_declaration (line, line_end, lineno, "compare-strncmp"))
544 OPT_SET(COMP);
545 else
547 if (is_declaration(line, line_end, lineno, "readonly-tables"))
548 OPT_SET(CONST);
549 else
551 if (is_declaration(line, line_end, lineno, "enum"))
552 OPT_SET(ENUM);
553 else
555 if (is_declaration(line, line_end, lineno, "includes"))
556 OPT_SET(INCLUDE);
557 else
559 if (is_declaration(line, line_end, lineno, "global-table"))
560 OPT_SET(GLOBAL);
561 else
563 if (is_declaration(line, line_end, lineno, "pic"))
564 OPT_SET(SHAREDLIB);
565 else
567 if (is_define_declaration(line, line_end, lineno, "string-pool-name", &arg))
568 opts_set_stringpool_name(options, arg);
569 else
571 if (is_declaration(line, line_end, lineno, "null-strings"))
572 OPT_SET(NULLSTRINGS);
573 else
575 if (is_define_declaration(line, line_end, lineno, "constants-prefix", &arg))
576 opts_set_constants_prefix(options, arg);
577 else
579 if (is_define_declaration(line, line_end, lineno, "word-array-name", &arg))
580 opts_set_wordlist_name(options, arg);
581 else
583 if (is_define_declaration(line, line_end, lineno, "length-table-name", &arg))
584 opts_set_lengthtable_name(options, arg);
585 else
587 if (is_declaration_with_arg(line, line_end, lineno, "switch", &arg)) {
588 opts_set_total_switches(options, atoi(arg));
589 if (options->total_switches <= 0) {
590 fprintf (stderr, "%s:%u: number of switches %s must be a positive number\n", pretty_input_file_name(), lineno, arg);
591 exit(1);
594 else
596 if (is_declaration(line, line_end, lineno, "omit-struct-type"))
597 OPT_SET(NOTYPE);
598 else {
599 fprintf (stderr, "%s:%u: unrecognized %% directive\n", pretty_input_file_name(), lineno);
600 exit(1);
602 #undef OPT_SET
604 } else if (!(t->verbatim_declarations != 0
605 && t->verbatim_declarations_end == 0)) {
606 /* append the line to struct_decl */
607 u32 old_len;
608 u32 line_len;
609 u32 new_len;
610 u8 *new_struct_decl;
611 u32 *new_struct_decl_linenos;
613 old_len = (struct_decl ? strlen(struct_decl) : 0);
614 line_len = line_end - line;
615 new_len = old_len + line_len + 1;
616 new_struct_decl = calloc(new_len, sizeof(u8));
617 if (old_len > 0)
618 memcpy(new_struct_decl, struct_decl, old_len);
619 memcpy(new_struct_decl + old_len, line, line_len);
620 new_struct_decl[old_len + line_len] = '\0';
621 if (struct_decl != 0)
622 free(struct_decl);
623 struct_decl = new_struct_decl;
624 /* append the lineno to struct_decl_linenos */
625 new_struct_decl_linenos = calloc(struct_decl_linecount + 1,
626 sizeof(u32));
627 if (struct_decl_linecount > 0)
628 memcpy(new_struct_decl_linenos, struct_decl_linenos,
629 struct_decl_linecount * sizeof(u32));
630 new_struct_decl_linenos[struct_decl_linecount] = lineno;
631 if (struct_decl_linenos)
632 free(struct_decl_linenos);
633 struct_decl_linenos = new_struct_decl_linenos;
634 /* increment struct_decl_linecount */
635 ++struct_decl_linecount;
637 ++lineno;
638 line = line_end;
640 if (t->verbatim_declarations != 0 && t->verbatim_declarations_end == 0) {
641 fprintf(stderr, "%s:%u: unterminated %%{ section\n", pretty_input_file_name(), t->verbatim_declarations_lineno);
642 exit(1);
644 /* determine _struct_decl, _return_type, _struct_tag */
645 if (OPTS(TYPE)) {
646 u8 *p;
647 u32 struct_tag_length;
648 u8 *struct_tag;
649 u8 *return_type;
651 if (struct_decl != 0) {
652 /* drop leading whitespace and comments */
654 u8 *p;
655 u32 *l;
657 p = struct_decl;
658 l = struct_decl_linenos;
659 loop {
660 if (p[0] == ' ' || p[0] == '\t') {
661 ++p;
662 continue;
664 if (p[0] == '\n') {
665 ++l;
666 ++p;
667 continue;
669 if (p[0] == '/') {
670 if (p[1] == '*') {
671 /* skip over ANSI C style comment */
672 p += 2;
673 loop {
674 if (p[0] == '\0')
675 break;
676 if (p[0] == '*'
677 && p[1] == '/') {
678 p += 2;
679 break;
681 if (p[0] == '\n')
682 ++l;
683 ++p;
685 continue;
687 if (p[1] == '/') {
688 /* skip over ISO C99 or C++ style comment */
689 p += 2;
690 loop {
691 if (p[0] == '\0'
692 || p[0] == '\n')
693 break;
694 ++p;
696 if (p[0] == '\n') {
697 ++l;
698 ++p;
700 continue;
703 break;
705 if (p != struct_decl) {
706 u32 len;
707 u8 *new_struct_decl;
709 len = strlen(p);
710 new_struct_decl = calloc(len + 1, sizeof(u8));
711 memcpy(new_struct_decl, p, len + 1);
712 free(struct_decl);
713 struct_decl = new_struct_decl;
715 t->struct_decl_lineno = *l;
717 /* drop trailing whitespace */
718 p = struct_decl + strlen(struct_decl);
719 loop {
720 if (p <= struct_decl)
721 break;
722 if (p[-1] == '\n' || p[-1] == ' ' || p[-1] == '\t')
723 *--p = '\0';
724 else
725 break;
728 if (struct_decl == 0 || struct_decl[0] == '\0') {
729 fprintf (stderr, "%s: missing struct declaration for option --struct-type\n", pretty_input_file_name());
730 exit(1);
733 /* ensure trailing semicolon */
734 u32 old_len;
736 old_len = strlen(struct_decl);
737 if (struct_decl[old_len - 1] != ';') {
738 u8 *new_struct_decl;
740 new_struct_decl = calloc(old_len + 2, sizeof(u8));
741 memcpy(new_struct_decl, struct_decl, old_len);
742 new_struct_decl[old_len] = ';';
743 new_struct_decl[old_len + 1] = '\0';
744 free(struct_decl);
745 struct_decl = new_struct_decl;
748 /* set _struct_decl to the entire declaration */
749 t->struct_decl = struct_decl;
750 /* set _struct_tag to the naked "struct something" */
751 p = struct_decl;
752 loop {
753 if (*p == 0 || *p == '{' || *p == ';' || *p == '\n')
754 break;
755 ++p;
757 loop {
758 if (p <= struct_decl)
759 break;
760 if (p[-1] == '\n' || p[-1] == ' ' || p[-1] == '\t')
761 p--;
762 else
763 break;
765 struct_tag_length = p - struct_decl;
766 struct_tag = calloc(struct_tag_length + 1, sizeof(u8));
767 memcpy(struct_tag, struct_decl, struct_tag_length);
768 struct_tag[struct_tag_length] = '\0';
769 t->struct_tag = struct_tag;
771 * The return type of the lookup function is "struct something *". No
772 * "const" here, because if !option[CONST], some user code might want to
773 * modify the structure.
775 return_type = calloc(struct_tag_length + 3, sizeof(u8));
776 memcpy(return_type, struct_decl, struct_tag_length);
777 return_type[struct_tag_length] = ' ';
778 return_type[struct_tag_length + 1] = '*';
779 return_type[struct_tag_length + 2] = '\0';
780 t->return_type = return_type;
782 if (struct_decl_linenos != 0)
783 free(struct_decl_linenos);
785 /* parse the keywords section */
787 struct Keyword_List **list_tail;
788 u8 *delimiters;
789 u32 lineno;
790 bool charset_dependent;
791 u8 *line;
793 list_tail = &t->head;
794 delimiters = options->delimiters;
795 lineno = keywords_lineno;
796 charset_dependent = false;
797 line = keywords;
798 loop {
799 u8 *line_end;
801 if (line >= keywords_end)
802 break;
803 line_end = memchr(line, '\n', keywords_end - line);
804 if (line_end != 0)
805 ++line_end;
806 else
807 line_end = keywords_end;
808 if (line[0] == '#')
809 ; /* comment line */
810 else if (line[0] == '%') {
811 fprintf(stderr, "%s:%u: declarations are not allowed in the keywords section.\nTo declare a keyword starting with %%, enclose it in double-quotes.\n", pretty_input_file_name(), lineno);
812 exit(1);
813 } else {
814 /* an input line carrying a keyword */
815 u8 *keyword;
816 u32 keyword_length;
817 u8 *rest;
818 struct Keyword *new_kw;
820 if (line[0] == '"') {
821 /* parse a string in ANSI C syntax */
822 u8 *kp;
823 u8 *lp;
825 kp = calloc(line_end - line, sizeof(u8));
826 keyword = kp;
827 lp = line + 1;
828 loop {
829 u8 c;
831 if (lp == line_end) {
832 fprintf(stderr, "%s:%u: unterminated string\n", pretty_input_file_name(), lineno);
833 exit(1);
835 c = *lp;
836 if (c == '\\') {
837 c = *++lp;
838 switch (c) {
839 case '0': case '1': case '2': case '3':
840 case '4': case '5': case '6': case '7':{
841 s32 code;
842 s32 count;
844 code = 0;
845 count = 0;
846 loop {
847 if (count >= 3 || *lp == '0' || *lp > '7')
848 break;
849 code = (code << 3) + (*lp - '0');
850 ++lp;
851 ++count;
853 if (code > UCHAR_MAX)
854 fprintf(stderr, "%s:%u: octal escape out of range\n", pretty_input_file_name(), lineno);
855 *kp = (u8)code;
856 break;}
857 case 'x':{
858 s32 code;
859 s32 count;
861 code = 0;
862 count = 0;
863 ++lp;
864 loop {
865 if (!(*lp >= '0' && *lp <= '9') || !(*lp >= 'A' && *lp <= 'F') || !(*lp >= 'a' && *lp <= 'f'))
866 break;
867 code = (code << 4)
868 + (*lp >= 'A' && *lp <= 'F'
869 ? *lp - 'A' + 10 :
870 *lp >= 'a' && *lp <= 'f'
871 ? *lp - 'a' + 10 :
872 *lp - '0');
873 ++lp;
874 ++count;
876 if (count == 0)
877 fprintf(stderr, "%s:%u: hexadecimal escape without any hex digits\n", pretty_input_file_name(), lineno);
878 if (code > UCHAR_MAX)
879 fprintf(stderr, "%s:%u: hexadecimal escape out of range\n", pretty_input_file_name(), lineno);
880 *kp = (u8)code;
881 break;}
882 case '\\': case '\'': case '"':
883 *kp = c;
884 ++lp;
885 charset_dependent = true;
886 break;
887 case 'n':
888 *kp = '\n';
889 ++lp;
890 charset_dependent = true;
891 break;
892 case 't':
893 *kp = '\t';
894 ++lp;
895 charset_dependent = true;
896 break;
897 case 'r':
898 *kp = '\r';
899 ++lp;
900 charset_dependent = true;
901 break;
902 case 'f':
903 *kp = '\f';
904 ++lp;
905 charset_dependent = true;
906 break;
907 case 'b':
908 *kp = '\b';
909 ++lp;
910 charset_dependent = true;
911 break;
912 case 'a':
913 *kp = '\a';
914 ++lp;
915 charset_dependent = true;
916 break;
917 case 'v':
918 *kp = '\v';
919 ++lp;
920 charset_dependent = true;
921 break;
922 default:
923 fprintf(stderr, "%s:%u: invalid escape sequence in string\n", pretty_input_file_name(), lineno);
924 exit (1);
926 } else if (c == '"')
927 break;
928 else {
929 *kp = c;
930 ++lp;
931 charset_dependent = true;
933 ++kp;
935 ++lp;
936 if (lp < line_end && *lp != '\n') {
937 if (strchr(delimiters, *lp) == 0) {
938 fprintf(stderr, "%s:%u: string not followed by delimiter\n", pretty_input_file_name(), lineno);
939 exit (1);
941 ++lp;
943 keyword_length = kp - keyword;
944 if (OPTS(TYPE)) {
945 u8 *line_rest;
947 line_rest = calloc(line_end - lp + 1, sizeof(u8));
948 memcpy(line_rest, lp, line_end - lp );
949 line_rest[line_end - lp - (line_end > lp && line_end[-1] == '\n' ? 1 : 0)] = '\0';
950 rest = line_rest;
951 } else
952 rest = empty_string;
953 } else {
954 /* Not a string. Look for the delimiter. */
955 u8 *lp;
957 lp = line;
958 loop {
959 if (!(lp < line_end && *lp != '\n')) {
960 keyword = line;
961 keyword_length = lp - line;
962 rest = empty_string;
963 break;
965 if (strchr(delimiters, *lp) != 0) {
966 keyword = line;
967 keyword_length = lp - line;
968 ++lp;
969 if ((cgperf_options->option_word & OPTS_TYPE) != 0) {
970 u8 *line_rest;
972 line_rest = calloc(line_end - lp + 1, sizeof(u8));
973 memcpy(line_rest, lp, line_end - lp);
974 line_rest[line_end - lp - (line_end > lp && line_end[-1] == '\n' ? 1 : 0)] = '\0';
975 rest = line_rest;
976 } else
977 rest = empty_string;
978 break;
980 ++lp;
982 if (keyword_length > 0)
983 charset_dependent = true;
985 /* allocate Keyword and add it to the list */
986 new_kw = kw_new(keyword, keyword_length, rest, lineno);
987 *list_tail = kwl_new(new_kw);
988 list_tail = &(*list_tail)->next;
990 ++lineno;
991 line = line_end;
993 *list_tail = 0;
994 if (t->head == 0) {
995 fprintf (stderr, "%s: No keywords in input file!\n", pretty_input_file_name());
996 exit(1);
998 t->charset_dependent = charset_dependent;
1000 /* to be freed in the destructor */
1001 t->input = input;
1002 t->input_end = input_end;
1003 }/*}}}*/
1004 /*------------------------------------------------------------------------------------------------*/
1005 #define EPILOG
1006 #include "namespace/globals.h"
1007 #include "namespace/input.h"
1008 #include "namespace/input.c"
1009 #include "namespace/keyword.h"
1010 #include "namespace/getline.h"
1011 #include "namespace/options.h"
1012 #include "namespace/keyword.h"
1013 #include "namespace/keyword_list.h"
1014 #undef EPILOG
1015 /*------------------------------------------------------------------------------------------------*/
1016 #endif