1 /* xgettext Lisp backend.
2 Copyright (C) 2001-2003, 2005-2009, 2015 Free Software Foundation,
5 This file was written by Bruno Haible <haible@clisp.cons.org>, 2001.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
40 #define _(s) gettext(s)
43 /* The Common Lisp syntax is described in the Common Lisp HyperSpec, chapter 2.
44 Since we are interested only in strings and in forms similar to
46 or (ngettext msgid msgid_plural ...)
47 we make the following simplifications:
49 - Assume the keywords and strings are in an ASCII compatible encoding.
50 This means we can read the input file one byte at a time, instead of
51 one character at a time. No need to worry about multibyte characters:
52 If they occur as part of identifiers, they most probably act as
53 constituent characters, and the byte based approach will do the same.
55 - Assume the read table is the standard Common Lisp read table.
56 Non-standard read tables are mostly used to read data, not programs.
58 - Assume the read table case is :UPCASE, and *READ-BASE* is 10.
60 - Don't interpret #n= and #n#, they usually don't appear in programs.
62 - Don't interpret #+, #-, they are unlikely to appear in a gettext form.
64 The remaining syntax rules are:
66 - The syntax code assigned to each character, and how tokens are built
67 up from characters (single escape, multiple escape etc.).
69 - Comment syntax: ';' and '#| ... |#'.
71 - String syntax: "..." with single escapes.
73 - Read macros and dispatch macro character '#'. Needed to be able to
74 tell which is the n-th argument of a function call.
79 /* ========================= Lexer customization. ========================= */
81 /* 'readtable_case' is the case conversion that is applied to non-escaped
82 parts of symbol tokens. In Common Lisp: (readtable-case *readtable*). */
92 static enum rtcase readtable_case = case_upcase;
94 /* 'read_base' is the assumed radix of integers and rational numbers.
95 In Common Lisp: *read-base*. */
96 static int read_base = 10;
98 /* 'read_preserve_whitespace' specifies whether a whitespace character
99 that terminates a token must be pushed back on the input stream.
100 We set it to true, because the special newline side effect in read_object()
101 requires that read_object() sees every newline not inside a token. */
102 static bool read_preserve_whitespace = true;
105 /* ====================== Keyword set customization. ====================== */
107 /* If true extract all strings. */
108 static bool extract_all = false;
110 static hash_table keywords;
111 static bool default_keywords = true;
115 x_lisp_extract_all ()
122 x_lisp_keyword (const char *name)
125 default_keywords = false;
129 struct callshape shape;
135 if (keywords.table == NULL)
136 hash_init (&keywords, 100);
138 split_keywordspec (name, &end, &shape);
140 /* The characters between name and end should form a valid Lisp symbol.
141 Extract the symbol name part. */
142 colon = strchr (name, ':');
143 if (colon != NULL && colon < end)
146 if (name < end && *name == ':')
148 colon = strchr (name, ':');
149 if (colon != NULL && colon < end)
155 symname = XNMALLOC (len, char);
156 for (i = 0; i < len; i++)
158 (name[i] >= 'a' && name[i] <= 'z' ? name[i] - 'a' + 'A' : name[i]);
160 insert_keyword_callshape (&keywords, symname, len, &shape);
164 /* Finish initializing the keywords hash table.
165 Called after argument processing, before each file is processed. */
169 if (default_keywords)
171 /* When adding new keywords here, also update the documentation in
173 x_lisp_keyword ("gettext"); /* I18N:GETTEXT */
174 x_lisp_keyword ("ngettext:1,2"); /* I18N:NGETTEXT */
175 x_lisp_keyword ("gettext-noop");
176 default_keywords = false;
181 init_flag_table_lisp ()
183 xgettext_record_flag ("gettext:1:pass-lisp-format");
184 xgettext_record_flag ("ngettext:1:pass-lisp-format");
185 xgettext_record_flag ("ngettext:2:pass-lisp-format");
186 xgettext_record_flag ("gettext-noop:1:pass-lisp-format");
187 xgettext_record_flag ("format:2:lisp-format");
191 /* ======================== Reading of characters. ======================== */
193 /* Real filename, used in error messages about the input file. */
194 static const char *real_file_name;
196 /* Logical filename and line number, used to label the extracted messages. */
197 static char *logical_file_name;
198 static int line_number;
200 /* The input file stream. */
204 /* Fetch the next character from the input file. */
213 error (EXIT_FAILURE, errno, _("\
214 error while reading \"%s\""), real_file_name);
222 /* Put back the last fetched character, not EOF. */
232 /* ========= Reading of tokens. See CLHS 2.2 "Reader Algorithm". ========= */
235 /* Syntax code. See CLHS 2.1.4 "Character Syntax Types". */
239 syntax_illegal, /* non-printable, except whitespace */
240 syntax_single_esc, /* '\' (single escape) */
241 syntax_multi_esc, /* '|' (multiple escape) */
242 syntax_constituent, /* everything else (constituent) */
243 syntax_whitespace, /* TAB,LF,FF,CR,' ' (whitespace) */
244 syntax_eof, /* EOF */
245 syntax_t_macro, /* '()'"' (terminating macro) */
246 syntax_nt_macro /* '#' (non-terminating macro) */
249 /* Returns the syntax code of a character. */
250 static enum syntax_code
251 syntax_code_of (unsigned char c)
256 return syntax_single_esc;
258 return syntax_multi_esc;
259 case '\t': case '\n': case '\f': case '\r': case ' ':
260 return syntax_whitespace;
261 case '(': case ')': case '\'': case '"': case ',': case ';': case '`':
262 return syntax_t_macro;
264 return syntax_nt_macro;
266 if (c < ' ' && c != '\b')
267 return syntax_illegal;
269 return syntax_constituent;
275 int ch; /* character */
276 enum syntax_code scode; /* syntax code */
279 /* Returns the next character and its syntax code. */
281 read_char_syntax (struct char_syntax *p)
286 p->scode = (c == EOF ? syntax_eof : syntax_code_of (c));
289 /* Every character in a token has an attribute assigned. The attributes
290 help during interpretation of the token. See
291 CLHS 2.3 "Interpretation of Tokens" for the possible interpretations,
292 and CLHS 2.1.4.2 "Constituent Traits". */
296 a_illg, /* invalid constituent */
297 a_pack_m, /* ':' package marker */
298 a_alpha, /* normal alphabetic */
299 a_escaped, /* alphabetic but not subject to case conversion */
303 a_extens, /* '_^' extension characters */
304 a_digit, /* '0123456789' */
305 a_letterdigit,/* 'A'-'Z','a'-'z' below base, except 'esfdlESFDL' */
306 a_expodigit, /* 'esfdlESFDL' below base */
307 a_letter, /* 'A'-'Z','a'-'z', except 'esfdlESFDL' */
308 a_expo /* 'esfdlESFDL' */
311 #define is_letter_attribute(a) ((a) >= a_letter)
312 #define is_number_attribute(a) ((a) >= a_ratio)
314 /* Returns the attribute of a character, assuming base 10. */
315 static enum attribute
316 attribute_of (unsigned char c)
330 case '0': case '1': case '2': case '3': case '4':
331 case '5': case '6': case '7': case '8': case '9':
333 case 'a': case 'b': case 'c': case 'g': case 'h': case 'i': case 'j':
334 case 'k': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
335 case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
336 case 'A': case 'B': case 'C': case 'G': case 'H': case 'I': case 'J':
337 case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
338 case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
340 case 'e': case 's': case 'd': case 'f': case 'l':
341 case 'E': case 'S': case 'D': case 'F': case 'L':
344 /* Treat everything as valid. Never return a_illg. */
351 unsigned char ch; /* character */
352 unsigned char attribute; /* attribute */
355 /* A token consists of a sequence of characters with associated attribute. */
358 int allocated; /* number of allocated 'token_char's */
359 int charcount; /* number of used 'token_char's */
360 struct token_char *chars; /* the token's constituents */
361 bool with_escape; /* whether single-escape or multiple escape occurs */
364 /* Initialize a 'struct token'. */
366 init_token (struct token *tp)
369 tp->chars = XNMALLOC (tp->allocated, struct token_char);
373 /* Free the memory pointed to by a 'struct token'. */
375 free_token (struct token *tp)
380 /* Ensure there is enough room in the token for one more character. */
382 grow_token (struct token *tp)
384 if (tp->charcount == tp->allocated)
387 tp->chars = (struct token_char *) xrealloc (tp->chars, tp->allocated * sizeof (struct token_char));
391 /* Read the next token. If 'first' is given, it points to the first
392 character, which has already been read.
393 The algorithm follows CLHS 2.2 "Reader Algorithm". */
395 read_token (struct token *tp, const struct char_syntax *first)
397 bool multiple_escape_flag;
398 struct char_syntax curr;
401 tp->with_escape = false;
403 multiple_escape_flag = false;
407 read_char_syntax (&curr);
409 for (;; read_char_syntax (&curr))
414 /* Invalid input. Be tolerant, no error message. */
418 case syntax_single_esc:
419 tp->with_escape = true;
420 read_char_syntax (&curr);
421 if (curr.scode == syntax_eof)
422 /* Invalid input. Be tolerant, no error message. */
425 tp->chars[tp->charcount].ch = curr.ch;
426 tp->chars[tp->charcount].attribute = a_escaped;
430 case syntax_multi_esc:
431 multiple_escape_flag = !multiple_escape_flag;
432 tp->with_escape = true;
435 case syntax_constituent:
436 case syntax_nt_macro:
438 if (multiple_escape_flag)
440 tp->chars[tp->charcount].ch = curr.ch;
441 tp->chars[tp->charcount].attribute = a_escaped;
446 tp->chars[tp->charcount].ch = curr.ch;
447 tp->chars[tp->charcount].attribute = attribute_of (curr.ch);
452 case syntax_whitespace:
454 if (multiple_escape_flag)
457 tp->chars[tp->charcount].ch = curr.ch;
458 tp->chars[tp->charcount].attribute = a_escaped;
463 if (curr.scode != syntax_whitespace || read_preserve_whitespace)
470 if (multiple_escape_flag)
471 /* Invalid input. Be tolerant, no error message. */
478 /* A potential number is a token which
479 1. consists only of digits, '+','-','/','^','_','.' and number markers.
480 The base for digits is context dependent, but always 10 if a dot '.'
481 occurs. A number marker is a non-digit letter which is not adjacent
482 to a non-digit letter.
483 2. has at least one digit.
484 3. starts with a digit, '+','-','.','^' or '_'.
485 4. does not end with '+' or '-'.
486 See CLHS 2.3.1.1 "Potential Numbers as Tokens".
490 has_a_dot (const struct token *tp)
492 int n = tp->charcount;
495 for (i = 0; i < n; i++)
496 if (tp->chars[i].attribute == a_dot)
502 all_a_number (const struct token *tp)
504 int n = tp->charcount;
507 for (i = 0; i < n; i++)
508 if (!is_number_attribute (tp->chars[i].attribute))
514 a_letter_to_digit (const struct token *tp, int base)
516 int n = tp->charcount;
519 for (i = 0; i < n; i++)
520 if (is_letter_attribute (tp->chars[i].attribute))
522 int c = tp->chars[i].ch;
526 if (c - 'A' + 10 < base)
527 tp->chars[i].attribute -= 2; /* a_letter -> a_letterdigit,
528 a_expo -> a_expodigit */
533 has_a_digit (const struct token *tp)
535 int n = tp->charcount;
538 for (i = 0; i < n; i++)
539 if (tp->chars[i].attribute == a_digit
540 || tp->chars[i].attribute == a_letterdigit
541 || tp->chars[i].attribute == a_expodigit)
547 has_adjacent_letters (const struct token *tp)
549 int n = tp->charcount;
552 for (i = 1; i < n; i++)
553 if (is_letter_attribute (tp->chars[i-1].attribute)
554 && is_letter_attribute (tp->chars[i].attribute))
560 is_potential_number (const struct token *tp, int *basep)
563 "A potential number cannot contain any escape characters." */
570 if (!all_a_number (tp))
573 a_letter_to_digit (tp, *basep);
575 if (!has_a_digit (tp))
578 if (has_adjacent_letters (tp))
581 if (!(tp->chars[0].attribute >= a_dot
582 && tp->chars[0].attribute <= a_expodigit))
585 if (tp->chars[tp->charcount - 1].attribute == a_sign)
591 /* A number is one of integer, ratio, float. Each has a particular syntax.
592 See CLHS 2.3.1 "Numbers as Tokens".
593 But note a mistake: The exponent rule should read:
594 exponent ::= exponent-marker [sign] {decimal-digit}+
595 (see 22.1.3.1.3 "Printing Floats"). */
605 static enum number_type
606 is_number (const struct token *tp, int *basep)
608 struct token_char *ptr_limit;
609 struct token_char *ptr1;
611 if (!is_potential_number (tp, basep))
614 /* is_potential_number guarantees
615 - all attributes are >= a_ratio,
616 - there is at least one a_digit or a_letterdigit or a_expodigit, and
617 - if there is an a_dot, then *basep = 10. */
619 ptr1 = &tp->chars[0];
620 ptr_limit = &tp->chars[tp->charcount];
622 if (ptr1->attribute == a_sign)
627 * { a_digit < base }+ { a_ratio { a_digit < base }+ | }
630 bool seen_a_ratio = false;
631 bool seen_a_digit = false; /* seen a digit in last digit block? */
632 struct token_char *ptr;
634 for (ptr = ptr1;; ptr++)
636 if (ptr >= ptr_limit)
645 if (ptr->attribute == a_digit
646 || ptr->attribute == a_letterdigit
647 || ptr->attribute == a_expodigit)
651 c = (c < 'A' ? c - '0' : c < 'a' ? c - 'A' + 10 : c - 'a' + 10);
656 else if (ptr->attribute == a_ratio)
658 if (seen_a_ratio || !seen_a_digit)
661 seen_a_digit = false;
670 * { a_digit }* { a_dot { a_digit }* | }
671 * { a_expo { a_sign | } { a_digit }+ | }
673 * If there is an exponent part, there must be digits before the dot or
674 * after the dot. The result is a float.
675 * If there is no exponen:
676 * If there is no dot, it would an integer in base 10, but is has already
677 * been verified to not be an integer in the current base.
679 * If there are digits after the dot, it's a float.
680 * Otherwise, if there are digits before the dot, it's an integer.
684 bool seen_a_dot = false;
685 bool seen_a_dot_with_leading_digits = false;
686 bool seen_a_digit = false; /* seen a digit in last digit block? */
687 struct token_char *ptr;
689 for (ptr = ptr1;; ptr++)
691 if (ptr >= ptr_limit)
698 if (seen_a_dot_with_leading_digits)
703 if (ptr->attribute == a_digit)
707 else if (ptr->attribute == a_dot)
713 seen_a_dot_with_leading_digits = true;
714 seen_a_digit = false;
716 else if (ptr->attribute == a_expo || ptr->attribute == a_expodigit)
722 if (!seen_a_dot_with_leading_digits || !seen_a_digit)
724 if (ptr >= ptr_limit)
726 if (ptr->attribute == a_sign)
728 seen_a_digit = false;
731 if (ptr >= ptr_limit)
733 if (ptr->attribute != a_digit)
743 /* A token representing a symbol must be case converted.
744 For portability, we convert only ASCII characters here. */
747 upcase_token (struct token *tp)
749 int n = tp->charcount;
752 for (i = 0; i < n; i++)
753 if (tp->chars[i].attribute != a_escaped)
755 unsigned char c = tp->chars[i].ch;
756 if (c >= 'a' && c <= 'z')
757 tp->chars[i].ch = c - 'a' + 'A';
762 downcase_token (struct token *tp)
764 int n = tp->charcount;
767 for (i = 0; i < n; i++)
768 if (tp->chars[i].attribute != a_escaped)
770 unsigned char c = tp->chars[i].ch;
771 if (c >= 'A' && c <= 'Z')
772 tp->chars[i].ch = c - 'A' + 'a';
777 case_convert_token (struct token *tp)
779 int n = tp->charcount;
782 switch (readtable_case)
797 bool seen_uppercase = false;
798 bool seen_lowercase = false;
799 for (i = 0; i < n; i++)
800 if (tp->chars[i].attribute != a_escaped)
802 unsigned char c = tp->chars[i].ch;
803 if (c >= 'a' && c <= 'z')
804 seen_lowercase = true;
805 if (c >= 'A' && c <= 'Z')
806 seen_uppercase = true;
824 /* ========================= Accumulating comments ========================= */
828 static size_t bufmax;
829 static size_t buflen;
840 if (buflen >= bufmax)
842 bufmax = 2 * bufmax + 10;
843 buffer = xrealloc (buffer, bufmax);
845 buffer[buflen++] = c;
849 comment_line_end (size_t chars_to_remove)
851 buflen -= chars_to_remove;
853 && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
855 if (chars_to_remove == 0 && buflen >= bufmax)
857 bufmax = 2 * bufmax + 10;
858 buffer = xrealloc (buffer, bufmax);
860 buffer[buflen] = '\0';
861 savable_comment_add (buffer);
865 /* These are for tracking whether comments count as immediately before
867 static int last_comment_line;
868 static int last_non_comment_line;
871 /* ========================= Accumulating messages ========================= */
874 static message_list_ty *mlp;
877 /* ============== Reading of objects. See CLHS 2 "Syntax". ============== */
880 /* We are only interested in symbols (e.g. GETTEXT or NGETTEXT) and strings.
881 Other objects need not to be represented precisely. */
884 t_symbol, /* symbol */
885 t_string, /* string */
886 t_other, /* other kind of real object */
887 t_dot, /* '.' pseudo object */
888 t_close, /* ')' pseudo object */
889 t_eof /* EOF marker */
894 enum object_type type;
895 struct token *token; /* for t_symbol and t_string */
896 int line_number_at_start; /* for t_string */
899 /* Free the memory pointed to by a 'struct object'. */
901 free_object (struct object *op)
903 if (op->type == t_symbol || op->type == t_string)
905 free_token (op->token);
910 /* Convert a t_symbol/t_string token to a char*. */
912 string_of_object (const struct object *op)
915 const struct token_char *p;
919 if (!(op->type == t_symbol || op->type == t_string))
921 n = op->token->charcount;
922 str = XNMALLOC (n + 1, char);
924 for (p = op->token->chars; n > 0; p++, n--)
930 /* Context lookup table. */
931 static flag_context_list_table_ty *flag_context_list_table;
933 /* Read the next object. */
935 read_object (struct object *op, flag_context_ty outer_context)
939 struct char_syntax curr;
941 read_char_syntax (&curr);
949 case syntax_whitespace:
951 /* Comments assumed to be grouped with a message must immediately
952 precede it, with no non-whitespace token on a line between
954 if (last_non_comment_line > last_comment_line)
955 savable_comment_reset ();
962 case syntax_single_esc:
963 case syntax_multi_esc:
964 case syntax_constituent:
965 /* Start reading a token. */
966 op->token = XMALLOC (struct token);
967 read_token (op->token, &curr);
968 last_non_comment_line = line_number;
970 /* Interpret the token. */
973 if (!op->token->with_escape
974 && op->token->charcount == 1
975 && op->token->chars[0].attribute == a_dot)
977 free_token (op->token);
982 /* Tokens consisting entirely of dots are illegal, but be tolerant
987 int base = read_base;
989 if (is_number (op->token, &base) != n_none)
991 free_token (op->token);
998 /* We interpret all other tokens as symbols (including 'reserved
999 tokens', i.e. potential numbers which are not numbers). */
1000 case_convert_token (op->token);
1001 op->type = t_symbol;
1004 case syntax_t_macro:
1005 case syntax_nt_macro:
1011 int arg = 0; /* Current argument number. */
1012 flag_context_list_iterator_ty context_iter;
1013 const struct callshapes *shapes = NULL;
1014 struct arglist_parser *argparser = NULL;
1018 struct object inner;
1019 flag_context_ty inner_context;
1022 inner_context = null_context;
1025 inherited_context (outer_context,
1026 flag_context_list_iterator_advance (
1029 read_object (&inner, inner_context);
1031 /* Recognize end of list. */
1032 if (inner.type == t_close)
1035 /* Don't bother converting "()" to "NIL". */
1036 last_non_comment_line = line_number;
1037 if (argparser != NULL)
1038 arglist_parser_done (argparser, arg);
1042 /* Dots are not allowed in every position.
1045 /* EOF inside list is illegal.
1047 if (inner.type == t_eof)
1052 /* This is the function position. */
1053 if (inner.type == t_symbol)
1055 char *symbol_name = string_of_object (&inner);
1058 void *keyword_value;
1060 /* Omit any package name. */
1061 i = inner.token->charcount;
1063 && inner.token->chars[i-1].attribute != a_pack_m)
1067 if (hash_find_entry (&keywords,
1068 symbol_name + prefix_len,
1069 strlen (symbol_name + prefix_len),
1072 shapes = (const struct callshapes *) keyword_value;
1074 argparser = arglist_parser_alloc (mlp, shapes);
1077 flag_context_list_iterator (
1078 flag_context_list_table_lookup (
1079 flag_context_list_table,
1080 symbol_name, strlen (symbol_name)));
1085 context_iter = null_context_list_iterator;
1089 /* These are the argument positions. */
1090 if (argparser != NULL && inner.type == t_string)
1091 arglist_parser_remember (argparser, arg,
1092 string_of_object (&inner),
1095 inner.line_number_at_start,
1099 free_object (&inner);
1102 if (argparser != NULL)
1103 arglist_parser_done (argparser, arg);
1106 last_non_comment_line = line_number;
1110 /* Tell the caller about the end of list.
1111 Unmatched closing parenthesis is illegal.
1114 last_non_comment_line = line_number;
1120 /* The ,@ handling inside lists is wrong anyway, because
1121 ,@form expands to an unknown number of elements. */
1122 if (c != EOF && c != '@' && c != '.')
1129 struct object inner;
1131 read_object (&inner, null_context);
1133 /* Dots and EOF are not allowed here. But be tolerant. */
1135 free_object (&inner);
1138 last_non_comment_line = line_number;
1144 bool all_semicolons = true;
1146 last_comment_line = line_number;
1151 if (c == EOF || c == '\n')
1154 all_semicolons = false;
1155 if (!all_semicolons)
1157 /* We skip all leading white space, but not EOLs. */
1158 if (!(buflen == 0 && (c == ' ' || c == '\t')))
1162 comment_line_end (0);
1168 op->token = XMALLOC (struct token);
1169 init_token (op->token);
1170 op->line_number_at_start = line_number;
1175 /* Invalid input. Be tolerant, no error message. */
1179 if (c == '\\') /* syntax_single_esc */
1183 /* Invalid input. Be tolerant, no error message. */
1186 grow_token (op->token);
1187 op->token->chars[op->token->charcount++].ch = c;
1189 op->type = t_string;
1195 pos.file_name = logical_file_name;
1196 pos.line_number = op->line_number_at_start;
1197 remember_a_message (mlp, NULL, string_of_object (op),
1199 NULL, savable_comment);
1201 last_non_comment_line = line_number;
1206 /* Dispatch macro handling. */
1214 /* Invalid input. Be tolerant, no error message. */
1219 if (!(c >= '0' && c <= '9'))
1238 struct object inner;
1239 read_object (&inner, null_context);
1240 /* Dots and EOF are not allowed here.
1242 free_object (&inner);
1244 last_non_comment_line = line_number;
1268 comment_line_end (0);
1294 /* We skip all leading white space. */
1295 if (!(buflen == 0 && (c == ' ' || c == '\t')))
1299 comment_line_end (1);
1307 /* EOF not allowed here. But be tolerant. */
1311 last_comment_line = line_number;
1318 struct char_syntax first;
1320 first.scode = syntax_single_esc;
1321 read_token (&token, &first);
1322 free_token (&token);
1324 last_non_comment_line = line_number;
1335 read_token (&token, NULL);
1336 free_token (&token);
1338 last_non_comment_line = line_number;
1343 /* Ignore read labels. */
1347 /* Don't bother looking up the corresponding object. */
1349 last_non_comment_line = line_number;
1354 /* Simply assume every feature expression is true. */
1356 struct object inner;
1357 read_object (&inner, null_context);
1358 /* Dots and EOF are not allowed here.
1360 free_object (&inner);
1366 last_non_comment_line = line_number;
1387 extract_lisp (FILE *f,
1388 const char *real_filename, const char *logical_filename,
1389 flag_context_list_table_ty *flag_table,
1390 msgdomain_list_ty *mdlp)
1392 mlp = mdlp->item[0]->messages;
1395 real_file_name = real_filename;
1396 logical_file_name = xstrdup (logical_filename);
1399 last_comment_line = -1;
1400 last_non_comment_line = -1;
1402 flag_context_list_table = flag_table;
1406 /* Eat tokens until eof is seen. When read_object returns
1407 due to an unbalanced closing parenthesis, just restart it. */
1410 struct object toplevel_object;
1412 read_object (&toplevel_object, null_context);
1414 if (toplevel_object.type == t_eof)
1417 free_object (&toplevel_object);
1421 /* Close scanner. */
1423 real_file_name = NULL;
1424 logical_file_name = NULL;