1 /* xgettext Lisp backend.
2 Copyright (C) 2001-2003, 2005 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 2, or (at your option)
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, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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;
135 if (keywords
.table
== NULL
)
136 init_hash (&keywords
, 100);
138 split_keywordspec (name
, &end
, &argnum1
, &argnum2
);
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
= (char *) xmalloc (len
);
156 for (i
= 0; i
< len
; i
++)
158 (name
[i
] >= 'a' && name
[i
] <= 'z' ? name
[i
] - 'a' + 'A' : name
[i
]);
162 insert_entry (&keywords
, symname
, len
,
163 (void *) (long) (argnum1
+ (argnum2
<< 10)));
167 /* Finish initializing the keywords hash table.
168 Called after argument processing, before each file is processed. */
172 if (default_keywords
)
174 x_lisp_keyword ("gettext"); /* I18N:GETTEXT */
175 x_lisp_keyword ("ngettext:1,2"); /* I18N:NGETTEXT */
176 x_lisp_keyword ("gettext-noop");
177 default_keywords
= false;
182 init_flag_table_lisp ()
184 xgettext_record_flag ("gettext:1:pass-lisp-format");
185 xgettext_record_flag ("ngettext:1:pass-lisp-format");
186 xgettext_record_flag ("ngettext:2:pass-lisp-format");
187 xgettext_record_flag ("gettext-noop:1:pass-lisp-format");
188 xgettext_record_flag ("format:2:lisp-format");
192 /* ======================== Reading of characters. ======================== */
194 /* Real filename, used in error messages about the input file. */
195 static const char *real_file_name
;
197 /* Logical filename and line number, used to label the extracted messages. */
198 static char *logical_file_name
;
199 static int line_number
;
201 /* The input file stream. */
205 /* Fetch the next character from the input file. */
214 error (EXIT_FAILURE
, errno
, _("\
215 error while reading \"%s\""), real_file_name
);
223 /* Put back the last fetched character, not EOF. */
233 /* ========= Reading of tokens. See CLHS 2.2 "Reader Algorithm". ========= */
236 /* Syntax code. See CLHS 2.1.4 "Character Syntax Types". */
240 syntax_illegal
, /* non-printable, except whitespace */
241 syntax_single_esc
, /* '\' (single escape) */
242 syntax_multi_esc
, /* '|' (multiple escape) */
243 syntax_constituent
, /* everything else (constituent) */
244 syntax_whitespace
, /* TAB,LF,FF,CR,' ' (whitespace) */
245 syntax_eof
, /* EOF */
246 syntax_t_macro
, /* '()'"' (terminating macro) */
247 syntax_nt_macro
/* '#' (non-terminating macro) */
250 /* Returns the syntax code of a character. */
251 static enum syntax_code
252 syntax_code_of (unsigned char c
)
257 return syntax_single_esc
;
259 return syntax_multi_esc
;
260 case '\t': case '\n': case '\f': case '\r': case ' ':
261 return syntax_whitespace
;
262 case '(': case ')': case '\'': case '"': case ',': case ';': case '`':
263 return syntax_t_macro
;
265 return syntax_nt_macro
;
267 if (c
< ' ' && c
!= '\b')
268 return syntax_illegal
;
270 return syntax_constituent
;
276 int ch
; /* character */
277 enum syntax_code scode
; /* syntax code */
280 /* Returns the next character and its syntax code. */
282 read_char_syntax (struct char_syntax
*p
)
287 p
->scode
= (c
== EOF
? syntax_eof
: syntax_code_of (c
));
290 /* Every character in a token has an attribute assigned. The attributes
291 help during interpretation of the token. See
292 CLHS 2.3 "Interpretation of Tokens" for the possible interpretations,
293 and CLHS 2.1.4.2 "Constituent Traits". */
297 a_illg
, /* invalid constituent */
298 a_pack_m
, /* ':' package marker */
299 a_alpha
, /* normal alphabetic */
300 a_escaped
, /* alphabetic but not subject to case conversion */
304 a_extens
, /* '_^' extension characters */
305 a_digit
, /* '0123456789' */
306 a_letterdigit
,/* 'A'-'Z','a'-'z' below base, except 'esfdlESFDL' */
307 a_expodigit
, /* 'esfdlESFDL' below base */
308 a_letter
, /* 'A'-'Z','a'-'z', except 'esfdlESFDL' */
309 a_expo
/* 'esfdlESFDL' */
312 #define is_letter_attribute(a) ((a) >= a_letter)
313 #define is_number_attribute(a) ((a) >= a_ratio)
315 /* Returns the attribute of a character, assuming base 10. */
316 static enum attribute
317 attribute_of (unsigned char c
)
331 case '0': case '1': case '2': case '3': case '4':
332 case '5': case '6': case '7': case '8': case '9':
334 case 'a': case 'b': case 'c': case 'g': case 'h': case 'i': case 'j':
335 case 'k': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
336 case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
337 case 'A': case 'B': case 'C': case 'G': case 'H': case 'I': case 'J':
338 case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
339 case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
341 case 'e': case 's': case 'd': case 'f': case 'l':
342 case 'E': case 'S': case 'D': case 'F': case 'L':
345 /* Treat everything as valid. Never return a_illg. */
352 unsigned char ch
; /* character */
353 unsigned char attribute
; /* attribute */
356 /* A token consists of a sequence of characters with associated attribute. */
359 int allocated
; /* number of allocated 'token_char's */
360 int charcount
; /* number of used 'token_char's */
361 struct token_char
*chars
; /* the token's constituents */
362 bool with_escape
; /* whether single-escape or multiple escape occurs */
365 /* Initialize a 'struct token'. */
367 init_token (struct token
*tp
)
371 (struct token_char
*) xmalloc (tp
->allocated
* sizeof (struct token_char
));
375 /* Free the memory pointed to by a 'struct token'. */
377 free_token (struct token
*tp
)
382 /* Ensure there is enough room in the token for one more character. */
384 grow_token (struct token
*tp
)
386 if (tp
->charcount
== tp
->allocated
)
389 tp
->chars
= (struct token_char
*) xrealloc (tp
->chars
, tp
->allocated
* sizeof (struct token_char
));
393 /* Read the next token. If 'first' is given, it points to the first
394 character, which has already been read.
395 The algorithm follows CLHS 2.2 "Reader Algorithm". */
397 read_token (struct token
*tp
, const struct char_syntax
*first
)
399 bool multiple_escape_flag
;
400 struct char_syntax curr
;
403 tp
->with_escape
= false;
405 multiple_escape_flag
= false;
409 read_char_syntax (&curr
);
411 for (;; read_char_syntax (&curr
))
416 /* Invalid input. Be tolerant, no error message. */
420 case syntax_single_esc
:
421 tp
->with_escape
= true;
422 read_char_syntax (&curr
);
423 if (curr
.scode
== syntax_eof
)
424 /* Invalid input. Be tolerant, no error message. */
427 tp
->chars
[tp
->charcount
].ch
= curr
.ch
;
428 tp
->chars
[tp
->charcount
].attribute
= a_escaped
;
432 case syntax_multi_esc
:
433 multiple_escape_flag
= !multiple_escape_flag
;
434 tp
->with_escape
= true;
437 case syntax_constituent
:
438 case syntax_nt_macro
:
440 if (multiple_escape_flag
)
442 tp
->chars
[tp
->charcount
].ch
= curr
.ch
;
443 tp
->chars
[tp
->charcount
].attribute
= a_escaped
;
448 tp
->chars
[tp
->charcount
].ch
= curr
.ch
;
449 tp
->chars
[tp
->charcount
].attribute
= attribute_of (curr
.ch
);
454 case syntax_whitespace
:
456 if (multiple_escape_flag
)
459 tp
->chars
[tp
->charcount
].ch
= curr
.ch
;
460 tp
->chars
[tp
->charcount
].attribute
= a_escaped
;
465 if (curr
.scode
!= syntax_whitespace
|| read_preserve_whitespace
)
472 if (multiple_escape_flag
)
473 /* Invalid input. Be tolerant, no error message. */
480 /* A potential number is a token which
481 1. consists only of digits, '+','-','/','^','_','.' and number markers.
482 The base for digits is context dependent, but always 10 if a dot '.'
483 occurs. A number marker is a non-digit letter which is not adjacent
484 to a non-digit letter.
485 2. has at least one digit.
486 3. starts with a digit, '+','-','.','^' or '_'.
487 4. does not end with '+' or '-'.
488 See CLHS 2.3.1.1 "Potential Numbers as Tokens".
492 has_a_dot (const struct token
*tp
)
494 int n
= tp
->charcount
;
497 for (i
= 0; i
< n
; i
++)
498 if (tp
->chars
[i
].attribute
== a_dot
)
504 all_a_number (const struct token
*tp
)
506 int n
= tp
->charcount
;
509 for (i
= 0; i
< n
; i
++)
510 if (!is_number_attribute (tp
->chars
[i
].attribute
))
516 a_letter_to_digit (const struct token
*tp
, int base
)
518 int n
= tp
->charcount
;
521 for (i
= 0; i
< n
; i
++)
522 if (is_letter_attribute (tp
->chars
[i
].attribute
))
524 int c
= tp
->chars
[i
].ch
;
528 if (c
- 'A' + 10 < base
)
529 tp
->chars
[i
].attribute
-= 2; /* a_letter -> a_letterdigit,
530 a_expo -> a_expodigit */
535 has_a_digit (const struct token
*tp
)
537 int n
= tp
->charcount
;
540 for (i
= 0; i
< n
; i
++)
541 if (tp
->chars
[i
].attribute
== a_digit
542 || tp
->chars
[i
].attribute
== a_letterdigit
543 || tp
->chars
[i
].attribute
== a_expodigit
)
549 has_adjacent_letters (const struct token
*tp
)
551 int n
= tp
->charcount
;
554 for (i
= 1; i
< n
; i
++)
555 if (is_letter_attribute (tp
->chars
[i
-1].attribute
)
556 && is_letter_attribute (tp
->chars
[i
].attribute
))
562 is_potential_number (const struct token
*tp
, int *basep
)
565 "A potential number cannot contain any escape characters." */
572 if (!all_a_number (tp
))
575 a_letter_to_digit (tp
, *basep
);
577 if (!has_a_digit (tp
))
580 if (has_adjacent_letters (tp
))
583 if (!(tp
->chars
[0].attribute
>= a_dot
584 && tp
->chars
[0].attribute
<= a_expodigit
))
587 if (tp
->chars
[tp
->charcount
- 1].attribute
== a_sign
)
593 /* A number is one of integer, ratio, float. Each has a particular syntax.
594 See CLHS 2.3.1 "Numbers as Tokens".
595 But note a mistake: The exponent rule should read:
596 exponent ::= exponent-marker [sign] {decimal-digit}+
597 (see 22.1.3.1.3 "Printing Floats"). */
607 static enum number_type
608 is_number (const struct token
*tp
, int *basep
)
610 struct token_char
*ptr_limit
;
611 struct token_char
*ptr1
;
613 if (!is_potential_number (tp
, basep
))
616 /* is_potential_number guarantees
617 - all attributes are >= a_ratio,
618 - there is at least one a_digit or a_letterdigit or a_expodigit, and
619 - if there is an a_dot, then *basep = 10. */
621 ptr1
= &tp
->chars
[0];
622 ptr_limit
= &tp
->chars
[tp
->charcount
];
624 if (ptr1
->attribute
== a_sign
)
629 * { a_digit < base }+ { a_ratio { a_digit < base }+ | }
632 bool seen_a_ratio
= false;
633 bool seen_a_digit
= false; /* seen a digit in last digit block? */
634 struct token_char
*ptr
;
636 for (ptr
= ptr1
;; ptr
++)
638 if (ptr
>= ptr_limit
)
647 if (ptr
->attribute
== a_digit
648 || ptr
->attribute
== a_letterdigit
649 || ptr
->attribute
== a_expodigit
)
653 c
= (c
< 'A' ? c
- '0' : c
< 'a' ? c
- 'A' + 10 : c
- 'a' + 10);
658 else if (ptr
->attribute
== a_ratio
)
660 if (seen_a_ratio
|| !seen_a_digit
)
663 seen_a_digit
= false;
672 * { a_digit }* { a_dot { a_digit }* | }
673 * { a_expo { a_sign | } { a_digit }+ | }
675 * If there is an exponent part, there must be digits before the dot or
676 * after the dot. The result is a float.
677 * If there is no exponen:
678 * If there is no dot, it would an integer in base 10, but is has already
679 * been verified to not be an integer in the current base.
681 * If there are digits after the dot, it's a float.
682 * Otherwise, if there are digits before the dot, it's an integer.
686 bool seen_a_dot
= false;
687 bool seen_a_dot_with_leading_digits
= false;
688 bool seen_a_digit
= false; /* seen a digit in last digit block? */
689 struct token_char
*ptr
;
691 for (ptr
= ptr1
;; ptr
++)
693 if (ptr
>= ptr_limit
)
700 if (seen_a_dot_with_leading_digits
)
705 if (ptr
->attribute
== a_digit
)
709 else if (ptr
->attribute
== a_dot
)
715 seen_a_dot_with_leading_digits
= true;
716 seen_a_digit
= false;
718 else if (ptr
->attribute
== a_expo
|| ptr
->attribute
== a_expodigit
)
724 if (!seen_a_dot_with_leading_digits
|| !seen_a_digit
)
726 if (ptr
>= ptr_limit
)
728 if (ptr
->attribute
== a_sign
)
730 seen_a_digit
= false;
733 if (ptr
>= ptr_limit
)
735 if (ptr
->attribute
!= a_digit
)
745 /* A token representing a symbol must be case converted.
746 For portability, we convert only ASCII characters here. */
749 upcase_token (struct token
*tp
)
751 int n
= tp
->charcount
;
754 for (i
= 0; i
< n
; i
++)
755 if (tp
->chars
[i
].attribute
!= a_escaped
)
757 unsigned char c
= tp
->chars
[i
].ch
;
758 if (c
>= 'a' && c
<= 'z')
759 tp
->chars
[i
].ch
= c
- 'a' + 'A';
764 downcase_token (struct token
*tp
)
766 int n
= tp
->charcount
;
769 for (i
= 0; i
< n
; i
++)
770 if (tp
->chars
[i
].attribute
!= a_escaped
)
772 unsigned char c
= tp
->chars
[i
].ch
;
773 if (c
>= 'A' && c
<= 'Z')
774 tp
->chars
[i
].ch
= c
- 'A' + 'a';
779 case_convert_token (struct token
*tp
)
781 int n
= tp
->charcount
;
784 switch (readtable_case
)
799 bool seen_uppercase
= false;
800 bool seen_lowercase
= false;
801 for (i
= 0; i
< n
; i
++)
802 if (tp
->chars
[i
].attribute
!= a_escaped
)
804 unsigned char c
= tp
->chars
[i
].ch
;
805 if (c
>= 'a' && c
<= 'z')
806 seen_lowercase
= true;
807 if (c
>= 'A' && c
<= 'Z')
808 seen_uppercase
= true;
826 /* ========================= Accumulating comments ========================= */
830 static size_t bufmax
;
831 static size_t buflen
;
842 if (buflen
>= bufmax
)
844 bufmax
= 2 * bufmax
+ 10;
845 buffer
= xrealloc (buffer
, bufmax
);
847 buffer
[buflen
++] = c
;
851 comment_line_end (size_t chars_to_remove
)
853 buflen
-= chars_to_remove
;
855 && (buffer
[buflen
- 1] == ' ' || buffer
[buflen
- 1] == '\t'))
857 if (chars_to_remove
== 0 && buflen
>= bufmax
)
859 bufmax
= 2 * bufmax
+ 10;
860 buffer
= xrealloc (buffer
, bufmax
);
862 buffer
[buflen
] = '\0';
863 xgettext_comment_add (buffer
);
867 /* These are for tracking whether comments count as immediately before
869 static int last_comment_line
;
870 static int last_non_comment_line
;
873 /* ========================= Accumulating messages ========================= */
876 static message_list_ty
*mlp
;
879 /* ============== Reading of objects. See CLHS 2 "Syntax". ============== */
882 /* We are only interested in symbols (e.g. GETTEXT or NGETTEXT) and strings.
883 Other objects need not to be represented precisely. */
886 t_symbol
, /* symbol */
887 t_string
, /* string */
888 t_other
, /* other kind of real object */
889 t_dot
, /* '.' pseudo object */
890 t_close
, /* ')' pseudo object */
891 t_eof
/* EOF marker */
896 enum object_type type
;
897 struct token
*token
; /* for t_symbol and t_string */
898 int line_number_at_start
; /* for t_string */
901 /* Free the memory pointed to by a 'struct object'. */
903 free_object (struct object
*op
)
905 if (op
->type
== t_symbol
|| op
->type
== t_string
)
907 free_token (op
->token
);
912 /* Convert a t_symbol/t_string token to a char*. */
914 string_of_object (const struct object
*op
)
917 const struct token_char
*p
;
921 if (!(op
->type
== t_symbol
|| op
->type
== t_string
))
923 n
= op
->token
->charcount
;
924 str
= (char *) xmalloc (n
+ 1);
926 for (p
= op
->token
->chars
; n
> 0; p
++, n
--)
932 /* Context lookup table. */
933 static flag_context_list_table_ty
*flag_context_list_table
;
935 /* Read the next object. */
937 read_object (struct object
*op
, flag_context_ty outer_context
)
941 struct char_syntax curr
;
943 read_char_syntax (&curr
);
951 case syntax_whitespace
:
953 /* Comments assumed to be grouped with a message must immediately
954 precede it, with no non-whitespace token on a line between
956 if (last_non_comment_line
> last_comment_line
)
957 xgettext_comment_reset ();
964 case syntax_single_esc
:
965 case syntax_multi_esc
:
966 case syntax_constituent
:
967 /* Start reading a token. */
968 op
->token
= (struct token
*) xmalloc (sizeof (struct token
));
969 read_token (op
->token
, &curr
);
970 last_non_comment_line
= line_number
;
972 /* Interpret the token. */
975 if (!op
->token
->with_escape
976 && op
->token
->charcount
== 1
977 && op
->token
->chars
[0].attribute
== a_dot
)
979 free_token (op
->token
);
984 /* Tokens consisting entirely of dots are illegal, but be tolerant
989 int base
= read_base
;
991 if (is_number (op
->token
, &base
) != n_none
)
993 free_token (op
->token
);
1000 /* We interpret all other tokens as symbols (including 'reserved
1001 tokens', i.e. potential numbers which are not numbers). */
1002 case_convert_token (op
->token
);
1003 op
->type
= t_symbol
;
1006 case syntax_t_macro
:
1007 case syntax_nt_macro
:
1013 int arg
= 0; /* Current argument number. */
1014 flag_context_list_iterator_ty context_iter
;
1015 int argnum1
= 0; /* First string position. */
1016 int argnum2
= 0; /* Plural string position. */
1017 message_ty
*plural_mp
= NULL
; /* Remember the msgid. */
1021 struct object inner
;
1022 flag_context_ty inner_context
;
1025 inner_context
= null_context
;
1028 inherited_context (outer_context
,
1029 flag_context_list_iterator_advance (
1032 read_object (&inner
, inner_context
);
1034 /* Recognize end of list. */
1035 if (inner
.type
== t_close
)
1038 /* Don't bother converting "()" to "NIL". */
1039 last_non_comment_line
= line_number
;
1043 /* Dots are not allowed in every position.
1046 /* EOF inside list is illegal.
1048 if (inner
.type
== t_eof
)
1053 /* This is the function position. */
1054 if (inner
.type
== t_symbol
)
1056 char *symbol_name
= string_of_object (&inner
);
1059 void *keyword_value
;
1061 /* Omit any package name. */
1062 i
= inner
.token
->charcount
;
1064 && inner
.token
->chars
[i
-1].attribute
!= a_pack_m
)
1068 if (find_entry (&keywords
,
1069 symbol_name
+ prefix_len
,
1070 strlen (symbol_name
+ prefix_len
),
1074 argnum1
= (int) (long) keyword_value
& ((1 << 10) - 1);
1075 argnum2
= (int) (long) keyword_value
>> 10;
1079 flag_context_list_iterator (
1080 flag_context_list_table_lookup (
1081 flag_context_list_table
,
1082 symbol_name
, strlen (symbol_name
)));
1087 context_iter
= null_context_list_iterator
;
1091 /* These are the argument positions.
1092 Extract a string if we have reached the right
1093 argument position. */
1096 if (inner
.type
== t_string
)
1101 pos
.file_name
= logical_file_name
;
1102 pos
.line_number
= inner
.line_number_at_start
;
1103 mp
= remember_a_message (mlp
, string_of_object (&inner
),
1104 inner_context
, &pos
);
1109 else if (arg
== argnum2
)
1111 if (inner
.type
== t_string
&& plural_mp
!= NULL
)
1115 pos
.file_name
= logical_file_name
;
1116 pos
.line_number
= inner
.line_number_at_start
;
1117 remember_a_message_plural (plural_mp
, string_of_object (&inner
),
1118 inner_context
, &pos
);
1123 free_object (&inner
);
1127 last_non_comment_line
= line_number
;
1131 /* Tell the caller about the end of list.
1132 Unmatched closing parenthesis is illegal.
1135 last_non_comment_line
= line_number
;
1141 /* The ,@ handling inside lists is wrong anyway, because
1142 ,@form expands to an unknown number of elements. */
1143 if (c
!= EOF
&& c
!= '@' && c
!= '.')
1150 struct object inner
;
1152 read_object (&inner
, null_context
);
1154 /* Dots and EOF are not allowed here. But be tolerant. */
1156 free_object (&inner
);
1159 last_non_comment_line
= line_number
;
1165 bool all_semicolons
= true;
1167 last_comment_line
= line_number
;
1172 if (c
== EOF
|| c
== '\n')
1175 all_semicolons
= false;
1176 if (!all_semicolons
)
1178 /* We skip all leading white space, but not EOLs. */
1179 if (!(buflen
== 0 && (c
== ' ' || c
== '\t')))
1183 comment_line_end (0);
1189 op
->token
= (struct token
*) xmalloc (sizeof (struct token
));
1190 init_token (op
->token
);
1191 op
->line_number_at_start
= line_number
;
1196 /* Invalid input. Be tolerant, no error message. */
1200 if (c
== '\\') /* syntax_single_esc */
1204 /* Invalid input. Be tolerant, no error message. */
1207 grow_token (op
->token
);
1208 op
->token
->chars
[op
->token
->charcount
++].ch
= c
;
1210 op
->type
= t_string
;
1216 pos
.file_name
= logical_file_name
;
1217 pos
.line_number
= op
->line_number_at_start
;
1218 remember_a_message (mlp
, string_of_object (op
),
1219 null_context
, &pos
);
1221 last_non_comment_line
= line_number
;
1226 /* Dispatch macro handling. */
1234 /* Invalid input. Be tolerant, no error message. */
1239 if (!(c
>= '0' && c
<= '9'))
1258 struct object inner
;
1259 read_object (&inner
, null_context
);
1260 /* Dots and EOF are not allowed here.
1262 free_object (&inner
);
1264 last_non_comment_line
= line_number
;
1288 comment_line_end (0);
1314 /* We skip all leading white space. */
1315 if (!(buflen
== 0 && (c
== ' ' || c
== '\t')))
1319 comment_line_end (1);
1327 /* EOF not allowed here. But be tolerant. */
1331 last_comment_line
= line_number
;
1338 struct char_syntax first
;
1340 first
.scode
= syntax_single_esc
;
1341 read_token (&token
, &first
);
1342 free_token (&token
);
1344 last_non_comment_line
= line_number
;
1355 read_token (&token
, NULL
);
1356 free_token (&token
);
1358 last_non_comment_line
= line_number
;
1363 /* Ignore read labels. */
1367 /* Don't bother looking up the corresponding object. */
1369 last_non_comment_line
= line_number
;
1374 /* Simply assume every feature expression is true. */
1376 struct object inner
;
1377 read_object (&inner
, null_context
);
1378 /* Dots and EOF are not allowed here.
1380 free_object (&inner
);
1386 last_non_comment_line
= line_number
;
1407 extract_lisp (FILE *f
,
1408 const char *real_filename
, const char *logical_filename
,
1409 flag_context_list_table_ty
*flag_table
,
1410 msgdomain_list_ty
*mdlp
)
1412 mlp
= mdlp
->item
[0]->messages
;
1415 real_file_name
= real_filename
;
1416 logical_file_name
= xstrdup (logical_filename
);
1419 last_comment_line
= -1;
1420 last_non_comment_line
= -1;
1422 flag_context_list_table
= flag_table
;
1426 /* Eat tokens until eof is seen. When read_object returns
1427 due to an unbalanced closing parenthesis, just restart it. */
1430 struct object toplevel_object
;
1432 read_object (&toplevel_object
, null_context
);
1434 if (toplevel_object
.type
== t_eof
)
1437 free_object (&toplevel_object
);
1441 /* Close scanner. */
1443 real_file_name
= NULL
;
1444 logical_file_name
= NULL
;