1 /* xgettext Lisp backend.
2 Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc.
4 This file was written by Bruno Haible <haible@clisp.cons.org>, 2001.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
39 #define _(s) gettext(s)
42 /* The Common Lisp syntax is described in the Common Lisp HyperSpec, chapter 2.
43 Since we are interested only in strings and in forms similar to
45 or (ngettext msgid msgid_plural ...)
46 we make the following simplifications:
48 - Assume the keywords and strings are in an ASCII compatible encoding.
49 This means we can read the input file one byte at a time, instead of
50 one character at a time. No need to worry about multibyte characters:
51 If they occur as part of identifiers, they most probably act as
52 constituent characters, and the byte based approach will do the same.
54 - Assume the read table is the standard Common Lisp read table.
55 Non-standard read tables are mostly used to read data, not programs.
57 - Assume the read table case is :UPCASE, and *READ-BASE* is 10.
59 - Don't interpret #n= and #n#, they usually don't appear in programs.
61 - Don't interpret #+, #-, they are unlikely to appear in a gettext form.
63 The remaining syntax rules are:
65 - The syntax code assigned to each character, and how tokens are built
66 up from characters (single escape, multiple escape etc.).
68 - Comment syntax: ';' and '#| ... |#'.
70 - String syntax: "..." with single escapes.
72 - Read macros and dispatch macro character '#'. Needed to be able to
73 tell which is the n-th argument of a function call.
78 /* ========================= Lexer customization. ========================= */
80 /* 'readtable_case' is the case conversion that is applied to non-escaped
81 parts of symbol tokens. In Common Lisp: (readtable-case *readtable*). */
91 static enum rtcase readtable_case = case_upcase;
93 /* 'read_base' is the assumed radix of integers and rational numbers.
94 In Common Lisp: *read-base*. */
95 static int read_base = 10;
97 /* 'read_preserve_whitespace' specifies whether a whitespace character
98 that terminates a token must be pushed back on the input stream.
99 We set it to true, because the special newline side effect in read_object()
100 requires that read_object() sees every newline not inside a token. */
101 static bool read_preserve_whitespace = true;
104 /* ====================== Keyword set customization. ====================== */
106 /* If true extract all strings. */
107 static bool extract_all = false;
109 static hash_table keywords;
110 static bool default_keywords = true;
114 x_lisp_extract_all ()
121 x_lisp_keyword (const char *name)
124 default_keywords = false;
128 struct callshape shape;
134 if (keywords.table == NULL)
135 hash_init (&keywords, 100);
137 split_keywordspec (name, &end, &shape);
139 /* The characters between name and end should form a valid Lisp symbol.
140 Extract the symbol name part. */
141 colon = strchr (name, ':');
142 if (colon != NULL && colon < end)
145 if (name < end && *name == ':')
147 colon = strchr (name, ':');
148 if (colon != NULL && colon < end)
154 symname = XNMALLOC (len, char);
155 for (i = 0; i < len; i++)
157 (name[i] >= 'a' && name[i] <= 'z' ? name[i] - 'a' + 'A' : name[i]);
159 insert_keyword_callshape (&keywords, symname, len, &shape);
163 /* Finish initializing the keywords hash table.
164 Called after argument processing, before each file is processed. */
168 if (default_keywords)
170 /* When adding new keywords here, also update the documentation in
172 x_lisp_keyword ("gettext"); /* I18N:GETTEXT */
173 x_lisp_keyword ("ngettext:1,2"); /* I18N:NGETTEXT */
174 x_lisp_keyword ("gettext-noop");
175 default_keywords = false;
180 init_flag_table_lisp ()
182 xgettext_record_flag ("gettext:1:pass-lisp-format");
183 xgettext_record_flag ("ngettext:1:pass-lisp-format");
184 xgettext_record_flag ("ngettext:2:pass-lisp-format");
185 xgettext_record_flag ("gettext-noop:1:pass-lisp-format");
186 xgettext_record_flag ("format:2:lisp-format");
190 /* ======================== Reading of characters. ======================== */
192 /* Real filename, used in error messages about the input file. */
193 static const char *real_file_name;
195 /* Logical filename and line number, used to label the extracted messages. */
196 static char *logical_file_name;
197 static int line_number;
199 /* The input file stream. */
203 /* Fetch the next character from the input file. */
212 error (EXIT_FAILURE, errno, _("\
213 error while reading \"%s\""), real_file_name);
221 /* Put back the last fetched character, not EOF. */
231 /* ========= Reading of tokens. See CLHS 2.2 "Reader Algorithm". ========= */
234 /* Syntax code. See CLHS 2.1.4 "Character Syntax Types". */
238 syntax_illegal, /* non-printable, except whitespace */
239 syntax_single_esc, /* '\' (single escape) */
240 syntax_multi_esc, /* '|' (multiple escape) */
241 syntax_constituent, /* everything else (constituent) */
242 syntax_whitespace, /* TAB,LF,FF,CR,' ' (whitespace) */
243 syntax_eof, /* EOF */
244 syntax_t_macro, /* '()'"' (terminating macro) */
245 syntax_nt_macro /* '#' (non-terminating macro) */
248 /* Returns the syntax code of a character. */
249 static enum syntax_code
250 syntax_code_of (unsigned char c)
255 return syntax_single_esc;
257 return syntax_multi_esc;
258 case '\t': case '\n': case '\f': case '\r': case ' ':
259 return syntax_whitespace;
260 case '(': case ')': case '\'': case '"': case ',': case ';': case '`':
261 return syntax_t_macro;
263 return syntax_nt_macro;
265 if (c < ' ' && c != '\b')
266 return syntax_illegal;
268 return syntax_constituent;
274 int ch; /* character */
275 enum syntax_code scode; /* syntax code */
278 /* Returns the next character and its syntax code. */
280 read_char_syntax (struct char_syntax *p)
285 p->scode = (c == EOF ? syntax_eof : syntax_code_of (c));
288 /* Every character in a token has an attribute assigned. The attributes
289 help during interpretation of the token. See
290 CLHS 2.3 "Interpretation of Tokens" for the possible interpretations,
291 and CLHS 2.1.4.2 "Constituent Traits". */
295 a_illg, /* invalid constituent */
296 a_pack_m, /* ':' package marker */
297 a_alpha, /* normal alphabetic */
298 a_escaped, /* alphabetic but not subject to case conversion */
302 a_extens, /* '_^' extension characters */
303 a_digit, /* '0123456789' */
304 a_letterdigit,/* 'A'-'Z','a'-'z' below base, except 'esfdlESFDL' */
305 a_expodigit, /* 'esfdlESFDL' below base */
306 a_letter, /* 'A'-'Z','a'-'z', except 'esfdlESFDL' */
307 a_expo /* 'esfdlESFDL' */
310 #define is_letter_attribute(a) ((a) >= a_letter)
311 #define is_number_attribute(a) ((a) >= a_ratio)
313 /* Returns the attribute of a character, assuming base 10. */
314 static enum attribute
315 attribute_of (unsigned char c)
329 case '0': case '1': case '2': case '3': case '4':
330 case '5': case '6': case '7': case '8': case '9':
332 case 'a': case 'b': case 'c': case 'g': case 'h': case 'i': case 'j':
333 case 'k': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
334 case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
335 case 'A': case 'B': case 'C': case 'G': case 'H': case 'I': case 'J':
336 case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
337 case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
339 case 'e': case 's': case 'd': case 'f': case 'l':
340 case 'E': case 'S': case 'D': case 'F': case 'L':
343 /* Treat everything as valid. Never return a_illg. */
350 unsigned char ch; /* character */
351 unsigned char attribute; /* attribute */
354 /* A token consists of a sequence of characters with associated attribute. */
357 int allocated; /* number of allocated 'token_char's */
358 int charcount; /* number of used 'token_char's */
359 struct token_char *chars; /* the token's constituents */
360 bool with_escape; /* whether single-escape or multiple escape occurs */
363 /* Initialize a 'struct token'. */
365 init_token (struct token *tp)
368 tp->chars = XNMALLOC (tp->allocated, struct token_char);
372 /* Free the memory pointed to by a 'struct token'. */
374 free_token (struct token *tp)
379 /* Ensure there is enough room in the token for one more character. */
381 grow_token (struct token *tp)
383 if (tp->charcount == tp->allocated)
386 tp->chars = (struct token_char *) xrealloc (tp->chars, tp->allocated * sizeof (struct token_char));
390 /* Read the next token. If 'first' is given, it points to the first
391 character, which has already been read.
392 The algorithm follows CLHS 2.2 "Reader Algorithm". */
394 read_token (struct token *tp, const struct char_syntax *first)
396 bool multiple_escape_flag;
397 struct char_syntax curr;
400 tp->with_escape = false;
402 multiple_escape_flag = false;
406 read_char_syntax (&curr);
408 for (;; read_char_syntax (&curr))
413 /* Invalid input. Be tolerant, no error message. */
417 case syntax_single_esc:
418 tp->with_escape = true;
419 read_char_syntax (&curr);
420 if (curr.scode == syntax_eof)
421 /* Invalid input. Be tolerant, no error message. */
424 tp->chars[tp->charcount].ch = curr.ch;
425 tp->chars[tp->charcount].attribute = a_escaped;
429 case syntax_multi_esc:
430 multiple_escape_flag = !multiple_escape_flag;
431 tp->with_escape = true;
434 case syntax_constituent:
435 case syntax_nt_macro:
437 if (multiple_escape_flag)
439 tp->chars[tp->charcount].ch = curr.ch;
440 tp->chars[tp->charcount].attribute = a_escaped;
445 tp->chars[tp->charcount].ch = curr.ch;
446 tp->chars[tp->charcount].attribute = attribute_of (curr.ch);
451 case syntax_whitespace:
453 if (multiple_escape_flag)
456 tp->chars[tp->charcount].ch = curr.ch;
457 tp->chars[tp->charcount].attribute = a_escaped;
462 if (curr.scode != syntax_whitespace || read_preserve_whitespace)
469 if (multiple_escape_flag)
470 /* Invalid input. Be tolerant, no error message. */
477 /* A potential number is a token which
478 1. consists only of digits, '+','-','/','^','_','.' and number markers.
479 The base for digits is context dependent, but always 10 if a dot '.'
480 occurs. A number marker is a non-digit letter which is not adjacent
481 to a non-digit letter.
482 2. has at least one digit.
483 3. starts with a digit, '+','-','.','^' or '_'.
484 4. does not end with '+' or '-'.
485 See CLHS 2.3.1.1 "Potential Numbers as Tokens".
489 has_a_dot (const struct token *tp)
491 int n = tp->charcount;
494 for (i = 0; i < n; i++)
495 if (tp->chars[i].attribute == a_dot)
501 all_a_number (const struct token *tp)
503 int n = tp->charcount;
506 for (i = 0; i < n; i++)
507 if (!is_number_attribute (tp->chars[i].attribute))
513 a_letter_to_digit (const struct token *tp, int base)
515 int n = tp->charcount;
518 for (i = 0; i < n; i++)
519 if (is_letter_attribute (tp->chars[i].attribute))
521 int c = tp->chars[i].ch;
525 if (c - 'A' + 10 < base)
526 tp->chars[i].attribute -= 2; /* a_letter -> a_letterdigit,
527 a_expo -> a_expodigit */
532 has_a_digit (const struct token *tp)
534 int n = tp->charcount;
537 for (i = 0; i < n; i++)
538 if (tp->chars[i].attribute == a_digit
539 || tp->chars[i].attribute == a_letterdigit
540 || tp->chars[i].attribute == a_expodigit)
546 has_adjacent_letters (const struct token *tp)
548 int n = tp->charcount;
551 for (i = 1; i < n; i++)
552 if (is_letter_attribute (tp->chars[i-1].attribute)
553 && is_letter_attribute (tp->chars[i].attribute))
559 is_potential_number (const struct token *tp, int *basep)
562 "A potential number cannot contain any escape characters." */
569 if (!all_a_number (tp))
572 a_letter_to_digit (tp, *basep);
574 if (!has_a_digit (tp))
577 if (has_adjacent_letters (tp))
580 if (!(tp->chars[0].attribute >= a_dot
581 && tp->chars[0].attribute <= a_expodigit))
584 if (tp->chars[tp->charcount - 1].attribute == a_sign)
590 /* A number is one of integer, ratio, float. Each has a particular syntax.
591 See CLHS 2.3.1 "Numbers as Tokens".
592 But note a mistake: The exponent rule should read:
593 exponent ::= exponent-marker [sign] {decimal-digit}+
594 (see 22.1.3.1.3 "Printing Floats"). */
604 static enum number_type
605 is_number (const struct token *tp, int *basep)
607 struct token_char *ptr_limit;
608 struct token_char *ptr1;
610 if (!is_potential_number (tp, basep))
613 /* is_potential_number guarantees
614 - all attributes are >= a_ratio,
615 - there is at least one a_digit or a_letterdigit or a_expodigit, and
616 - if there is an a_dot, then *basep = 10. */
618 ptr1 = &tp->chars[0];
619 ptr_limit = &tp->chars[tp->charcount];
621 if (ptr1->attribute == a_sign)
626 * { a_digit < base }+ { a_ratio { a_digit < base }+ | }
629 bool seen_a_ratio = false;
630 bool seen_a_digit = false; /* seen a digit in last digit block? */
631 struct token_char *ptr;
633 for (ptr = ptr1;; ptr++)
635 if (ptr >= ptr_limit)
644 if (ptr->attribute == a_digit
645 || ptr->attribute == a_letterdigit
646 || ptr->attribute == a_expodigit)
650 c = (c < 'A' ? c - '0' : c < 'a' ? c - 'A' + 10 : c - 'a' + 10);
655 else if (ptr->attribute == a_ratio)
657 if (seen_a_ratio || !seen_a_digit)
660 seen_a_digit = false;
669 * { a_digit }* { a_dot { a_digit }* | }
670 * { a_expo { a_sign | } { a_digit }+ | }
672 * If there is an exponent part, there must be digits before the dot or
673 * after the dot. The result is a float.
674 * If there is no exponen:
675 * If there is no dot, it would an integer in base 10, but is has already
676 * been verified to not be an integer in the current base.
678 * If there are digits after the dot, it's a float.
679 * Otherwise, if there are digits before the dot, it's an integer.
683 bool seen_a_dot = false;
684 bool seen_a_dot_with_leading_digits = false;
685 bool seen_a_digit = false; /* seen a digit in last digit block? */
686 struct token_char *ptr;
688 for (ptr = ptr1;; ptr++)
690 if (ptr >= ptr_limit)
697 if (seen_a_dot_with_leading_digits)
702 if (ptr->attribute == a_digit)
706 else if (ptr->attribute == a_dot)
712 seen_a_dot_with_leading_digits = true;
713 seen_a_digit = false;
715 else if (ptr->attribute == a_expo || ptr->attribute == a_expodigit)
721 if (!seen_a_dot_with_leading_digits || !seen_a_digit)
723 if (ptr >= ptr_limit)
725 if (ptr->attribute == a_sign)
727 seen_a_digit = false;
730 if (ptr >= ptr_limit)
732 if (ptr->attribute != a_digit)
742 /* A token representing a symbol must be case converted.
743 For portability, we convert only ASCII characters here. */
746 upcase_token (struct token *tp)
748 int n = tp->charcount;
751 for (i = 0; i < n; i++)
752 if (tp->chars[i].attribute != a_escaped)
754 unsigned char c = tp->chars[i].ch;
755 if (c >= 'a' && c <= 'z')
756 tp->chars[i].ch = c - 'a' + 'A';
761 downcase_token (struct token *tp)
763 int n = tp->charcount;
766 for (i = 0; i < n; i++)
767 if (tp->chars[i].attribute != a_escaped)
769 unsigned char c = tp->chars[i].ch;
770 if (c >= 'A' && c <= 'Z')
771 tp->chars[i].ch = c - 'A' + 'a';
776 case_convert_token (struct token *tp)
778 int n = tp->charcount;
781 switch (readtable_case)
796 bool seen_uppercase = false;
797 bool seen_lowercase = false;
798 for (i = 0; i < n; i++)
799 if (tp->chars[i].attribute != a_escaped)
801 unsigned char c = tp->chars[i].ch;
802 if (c >= 'a' && c <= 'z')
803 seen_lowercase = true;
804 if (c >= 'A' && c <= 'Z')
805 seen_uppercase = true;
823 /* ========================= Accumulating comments ========================= */
827 static size_t bufmax;
828 static size_t buflen;
839 if (buflen >= bufmax)
841 bufmax = 2 * bufmax + 10;
842 buffer = xrealloc (buffer, bufmax);
844 buffer[buflen++] = c;
848 comment_line_end (size_t chars_to_remove)
850 buflen -= chars_to_remove;
852 && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
854 if (chars_to_remove == 0 && buflen >= bufmax)
856 bufmax = 2 * bufmax + 10;
857 buffer = xrealloc (buffer, bufmax);
859 buffer[buflen] = '\0';
860 savable_comment_add (buffer);
864 /* These are for tracking whether comments count as immediately before
866 static int last_comment_line;
867 static int last_non_comment_line;
870 /* ========================= Accumulating messages ========================= */
873 static message_list_ty *mlp;
876 /* ============== Reading of objects. See CLHS 2 "Syntax". ============== */
879 /* We are only interested in symbols (e.g. GETTEXT or NGETTEXT) and strings.
880 Other objects need not to be represented precisely. */
883 t_symbol, /* symbol */
884 t_string, /* string */
885 t_other, /* other kind of real object */
886 t_dot, /* '.' pseudo object */
887 t_close, /* ')' pseudo object */
888 t_eof /* EOF marker */
893 enum object_type type;
894 struct token *token; /* for t_symbol and t_string */
895 int line_number_at_start; /* for t_string */
898 /* Free the memory pointed to by a 'struct object'. */
900 free_object (struct object *op)
902 if (op->type == t_symbol || op->type == t_string)
904 free_token (op->token);
909 /* Convert a t_symbol/t_string token to a char*. */
911 string_of_object (const struct object *op)
914 const struct token_char *p;
918 if (!(op->type == t_symbol || op->type == t_string))
920 n = op->token->charcount;
921 str = XNMALLOC (n + 1, char);
923 for (p = op->token->chars; n > 0; p++, n--)
929 /* Context lookup table. */
930 static flag_context_list_table_ty *flag_context_list_table;
932 /* Read the next object. */
934 read_object (struct object *op, flag_context_ty outer_context)
938 struct char_syntax curr;
940 read_char_syntax (&curr);
948 case syntax_whitespace:
950 /* Comments assumed to be grouped with a message must immediately
951 precede it, with no non-whitespace token on a line between
953 if (last_non_comment_line > last_comment_line)
954 savable_comment_reset ();
961 case syntax_single_esc:
962 case syntax_multi_esc:
963 case syntax_constituent:
964 /* Start reading a token. */
965 op->token = XMALLOC (struct token);
966 read_token (op->token, &curr);
967 last_non_comment_line = line_number;
969 /* Interpret the token. */
972 if (!op->token->with_escape
973 && op->token->charcount == 1
974 && op->token->chars[0].attribute == a_dot)
976 free_token (op->token);
981 /* Tokens consisting entirely of dots are illegal, but be tolerant
986 int base = read_base;
988 if (is_number (op->token, &base) != n_none)
990 free_token (op->token);
997 /* We interpret all other tokens as symbols (including 'reserved
998 tokens', i.e. potential numbers which are not numbers). */
999 case_convert_token (op->token);
1000 op->type = t_symbol;
1003 case syntax_t_macro:
1004 case syntax_nt_macro:
1010 int arg = 0; /* Current argument number. */
1011 flag_context_list_iterator_ty context_iter;
1012 const struct callshapes *shapes = NULL;
1013 struct arglist_parser *argparser = NULL;
1017 struct object inner;
1018 flag_context_ty inner_context;
1021 inner_context = null_context;
1024 inherited_context (outer_context,
1025 flag_context_list_iterator_advance (
1028 read_object (&inner, inner_context);
1030 /* Recognize end of list. */
1031 if (inner.type == t_close)
1034 /* Don't bother converting "()" to "NIL". */
1035 last_non_comment_line = line_number;
1036 if (argparser != NULL)
1037 arglist_parser_done (argparser, arg);
1041 /* Dots are not allowed in every position.
1044 /* EOF inside list is illegal.
1046 if (inner.type == t_eof)
1051 /* This is the function position. */
1052 if (inner.type == t_symbol)
1054 char *symbol_name = string_of_object (&inner);
1057 void *keyword_value;
1059 /* Omit any package name. */
1060 i = inner.token->charcount;
1062 && inner.token->chars[i-1].attribute != a_pack_m)
1066 if (hash_find_entry (&keywords,
1067 symbol_name + prefix_len,
1068 strlen (symbol_name + prefix_len),
1071 shapes = (const struct callshapes *) keyword_value;
1073 argparser = arglist_parser_alloc (mlp, shapes);
1076 flag_context_list_iterator (
1077 flag_context_list_table_lookup (
1078 flag_context_list_table,
1079 symbol_name, strlen (symbol_name)));
1084 context_iter = null_context_list_iterator;
1088 /* These are the argument positions. */
1089 if (argparser != NULL && inner.type == t_string)
1090 arglist_parser_remember (argparser, arg,
1091 string_of_object (&inner),
1094 inner.line_number_at_start,
1098 free_object (&inner);
1101 if (argparser != NULL)
1102 arglist_parser_done (argparser, arg);
1105 last_non_comment_line = line_number;
1109 /* Tell the caller about the end of list.
1110 Unmatched closing parenthesis is illegal.
1113 last_non_comment_line = line_number;
1119 /* The ,@ handling inside lists is wrong anyway, because
1120 ,@form expands to an unknown number of elements. */
1121 if (c != EOF && c != '@' && c != '.')
1128 struct object inner;
1130 read_object (&inner, null_context);
1132 /* Dots and EOF are not allowed here. But be tolerant. */
1134 free_object (&inner);
1137 last_non_comment_line = line_number;
1143 bool all_semicolons = true;
1145 last_comment_line = line_number;
1150 if (c == EOF || c == '\n')
1153 all_semicolons = false;
1154 if (!all_semicolons)
1156 /* We skip all leading white space, but not EOLs. */
1157 if (!(buflen == 0 && (c == ' ' || c == '\t')))
1161 comment_line_end (0);
1167 op->token = XMALLOC (struct token);
1168 init_token (op->token);
1169 op->line_number_at_start = line_number;
1174 /* Invalid input. Be tolerant, no error message. */
1178 if (c == '\\') /* syntax_single_esc */
1182 /* Invalid input. Be tolerant, no error message. */
1185 grow_token (op->token);
1186 op->token->chars[op->token->charcount++].ch = c;
1188 op->type = t_string;
1194 pos.file_name = logical_file_name;
1195 pos.line_number = op->line_number_at_start;
1196 remember_a_message (mlp, NULL, string_of_object (op),
1198 NULL, savable_comment);
1200 last_non_comment_line = line_number;
1205 /* Dispatch macro handling. */
1213 /* Invalid input. Be tolerant, no error message. */
1218 if (!(c >= '0' && c <= '9'))
1237 struct object inner;
1238 read_object (&inner, null_context);
1239 /* Dots and EOF are not allowed here.
1241 free_object (&inner);
1243 last_non_comment_line = line_number;
1267 comment_line_end (0);
1293 /* We skip all leading white space. */
1294 if (!(buflen == 0 && (c == ' ' || c == '\t')))
1298 comment_line_end (1);
1306 /* EOF not allowed here. But be tolerant. */
1310 last_comment_line = line_number;
1317 struct char_syntax first;
1319 first.scode = syntax_single_esc;
1320 read_token (&token, &first);
1321 free_token (&token);
1323 last_non_comment_line = line_number;
1334 read_token (&token, NULL);
1335 free_token (&token);
1337 last_non_comment_line = line_number;
1342 /* Ignore read labels. */
1346 /* Don't bother looking up the corresponding object. */
1348 last_non_comment_line = line_number;
1353 /* Simply assume every feature expression is true. */
1355 struct object inner;
1356 read_object (&inner, null_context);
1357 /* Dots and EOF are not allowed here.
1359 free_object (&inner);
1365 last_non_comment_line = line_number;
1386 extract_lisp (FILE *f,
1387 const char *real_filename, const char *logical_filename,
1388 flag_context_list_table_ty *flag_table,
1389 msgdomain_list_ty *mdlp)
1391 mlp = mdlp->item[0]->messages;
1394 real_file_name = real_filename;
1395 logical_file_name = xstrdup (logical_filename);
1398 last_comment_line = -1;
1399 last_non_comment_line = -1;
1401 flag_context_list_table = flag_table;
1405 /* Eat tokens until eof is seen. When read_object returns
1406 due to an unbalanced closing parenthesis, just restart it. */
1409 struct object toplevel_object;
1411 read_object (&toplevel_object, null_context);
1413 if (toplevel_object.type == t_eof)
1416 free_object (&toplevel_object);
1420 /* Close scanner. */
1422 real_file_name = NULL;
1423 logical_file_name = NULL;